Classes and Objects
● Class: A blueprint for creating objects. Defined using the class keyword.
● Object: An instance of a class, containing data (attributes) and behavior (methods)
Example:.
class Dog:
sound = "bark"
dog1 = Dog() # Creating object from class
print(dog1.sound) # Accessing the class
Using __init__() Function
In Python, class has __init__() function which automatically initializes object attributes when an
object is created. The __init__() method is the constructor in Python.
class Dog:
species = "Canine" # Class attribute
def __init__(self, name, age):
self.name = name # Instance attribute
self.age = age # Instance attribute
# Creating an object of the Dog class
dog1 = Dog("Buddy", 3)
print(dog1.name)
print(dog1.species)
Output:
Buddy
3
__str__() Method
__str__ method in Python allows us to define a custom string representation of an
object. By default, when we print an object or convert it to a string using str(),
class Dog:
def __init__(self, name, age):
self.name = name
self.age = age
def __str__(self):
return f"{self.name} is {self.age} years old."
dog1 = Dog("Buddy", 3)
dog2 = Dog("Charlie", 5)
print(dog1)
print(dog2)
Output:
Buddy is 3 years old
Charlie is 5 years old
Inheritance and Polymorphism
Inheritance: Allows a class (child) to inherit attributes and methods from another class
(parent).
Single inheritance:
# Base class
class Parent:
def func1(self):
print("This function is in parent class.")
# Derived class
class Child(Parent):
def func2(self):
print("This function is in child class.")
# Driver code
obj = Child()
obj.func1()
obj.func2()
Output
This function is in parent class.
This function is in child class.
Multiple Inheritance:
When a class can be derived from more than one base class this type of inheritance is
called multiple inheritances. In multiple inheritances, all the features of the base
classes are inherited into the derived class.
# Base class 1
class Mother:
mothername = ""
def mother(self):
print(self.mothername)
# Base class 2
class Father:
fathername = ""
def father(self):
print(self.fathername)
# Derived class
class Son(Mother, Father):
def parents(self):
print("Father :", self.fathername)
print("Mother :", self.mothername)
# Driver code
s1 = Son()
s1.fathername = "RAM"
s1.mothername = "SITA"
s1.parents()
Output
Father : RAM
Mother : SITA
Multilevel Inheritance :
In multilevel inheritance, features of the base class and the derived class are
further inherited into the new derived class. This is similar to a relationship
representing a child and a grandfather.
# Base class
class Grandfather:
def __init__(self, grandfathername):
self.grandfathername = grandfathername
# Intermediate class
class Father(Grandfather):
def __init__(self, fathername, grandfathername):
self.fathername = fathername
# Call the constructor of Grandfather
Grandfather.__init__(self, grandfathername)
# Derived class
class Son(Father):
def __init__(self, sonname, fathername, grandfathername):
self.sonname = sonname
# Call the constructor of Father
Father.__init__(self, fathername, grandfathername)
def print_name(self):
print('Grandfather name :', self.grandfathername)
print('Father name :', self.fathername)
print('Son name :', self.sonname)
# Driver code
s1 = Son('Prince', 'Rampal', 'Lal mani')
print(s1.grandfathername)
s1.print_name()
Output
Lal mani
Grandfather name : Lal mani
Father name : Rampal
Son name : Prince
Hierarchical Inheritance:
When more than one derived class are created from a single base this type of
inheritance is called hierarchical inheritance. In this program, we have a
parent (base) class and two child (derived) classes.
# Base class
class Parent:
def func1(self):
print("This function is in parent class.")
# Derived class 1
class Child1(Parent):
def func2(self):
print("This function is in child 1.")
# Derived class 2
class Child2(Parent):
def func3(self):
print("This function is in child 2.")
# Driver code
object1 = Child1()
object2 = Child2()
object1.func1()
object1.func2()
object2.func1()
object2.func3()
Output
This function is in parent class.
This function is in child 1.
This function is in parent class.
This function is in child 2.
Hybrid Inheritance:
Hybrid inheritance is a combination of more than one type of inheritance. It
uses a mix like single, multiple, or multilevel inheritance within the same
program. Python's method resolution order (MRO) handles such cases.
# Base class
class School:
def func1(self):
print("This function is in school.")
# Derived class 1 (Single Inheritance)
class Student1(School):
def func2(self):
print("This function is in student 1.")
# Derived class 2 (Another Single Inheritance)
class Student2(School):
def func3(self):
print("This function is in student 2.")
# Derived class 3 (Multiple Inheritance)
class Student3(Student1, School):
def func4(self):
print("This function is in student 3.")
# Driver code
obj = Student3()
obj.func1()
obj.func2()
Output
This function is in school.
This function is in student 1.
Polymorphism: Enables using a single interface to represent different data types.
Methods in different classes can have the same name but behave differently.
import math
class Shape:
def area(self):
pass
class Circle(Shape):
def __init__(self, radius):
self.radius = radius
def area(self):
return math.pi * self.radius ** 2
class Rectangle(Shape):
def __init__(self, width, height):
self.width = width
self.height = height
def area(self):
return self.width * self.height
class Triangle(Shape):
def __init__(self, base, height):
self.base = base
self.height = height
def area(self):
return 0.5 * self.base * self.height
# Calculate areas
circle = Circle(5)
rectangle = Rectangle(4, 6)
triangle = Triangle(3, 4)
shapes = [circle, rectangle, triangle]
for shape in shapes:
print(f"Area of {type(shape).__name__}: {shape.area()}")
3. Class and Static Methods
● Class Method: Defined using the @classmethod decorator. It takes cls as the first
parameter and can modify class state.
class Car:
wheels = 4
@classmethod
def set_wheels(cls, count):
cls.wheels = count
Static Method: Defined using the @staticmethod decorator. It doesn't take self or cls as
the first parameter and doesn't modify object or class state.
class Car:
@staticmethod
def is_motorized():
return True
4. Dunder (Magic) Methods and Operator Overloading
Dunder Methods: Special methods that begin and end with double underscores. They allow
customization of default behavior.
These are methods in Python classes that are distinguished by having double
underscores at both the beginning and the end of their names (e.g., __init__,
__add__, __str__).
def __init__(self, name, age):
self.name = name # Instance attribute
self.age = age # Instance attribute
5. Operator Overloading
Operator overloading in Python allows same operator to work in different
ways depending on data type.
● Python built-in data types allow + operator can add numbers, join
strings or merge lists and * operator can be used to repeat instances
of a string.
● Python also allows to do operator overloading for user defined
classes by writing methods like __add__(), __mul__(), __sub__(),,
__lt__(), __gt__() and __eq__() to make objects work for
operators like +, *, -, <, > and == respectively.
● We cannot override or change the operator behavior of built-in
types (like int, str, list) globally; but we can subclass them (or
define your own class) and implement the special methods
class Complex:
def __init__(self, a, b):
self.a = a
self.b = b
def __add__(self, other):
return self.a + other.a, self.b + other.b
Ob1 = Complex(1, 2)
Ob2 = Complex(2, 3)
Ob3 = Ob1 + Ob2
print(Ob3)
Output
(3, 5)
Abstract Base Classes and Interfaces
An Abstract Base Class (ABC) defines methods that must be implemented
by its subclasses, ensuring that the subclasses follow a consistent structure.
ABCs allow you to define common interfaces that various subclasses can
implement while enforcing a level of abstraction.
Python provides the abc module to define ABCs and enforce the
implementation of abstract methods in subclasses.
Example: This example shows an abstract class Animal with an abstract
method sound() and a concrete subclass Dog that implements it.
from abc import ABC, abstractmethod
class Animal(ABC):
@abstractmethod
def sound(self):
pass
class Dog(Animal):
def sound(self):
return "Bark"
dog = Dog()
print(dog.sound())
● Define the Interface:
● Create a class that inherits from ABC (from the abc module).
● Decorate the methods that constitute the interface with
@abstractmethod. These methods will have no implementation in the
interface class itself.
from abc import ABC, abstractmethod
class MyInterface(ABC):
@abstractmethod
def method_a(self):
pass
@abstractmethod
def method_b(self):
pass
Case Study: Inventory Management System
from abc import ABC, abstractmethod
class Product(ABC):
def __init__(self, name, price):
self.name = name
self.price = price
@abstractmethod
def display(self):
pass
class Electronics(Product):
def display(self):
print(f"Electronics: {self.name}, Price: {self.price}")
class Clothing(Product):
def display(self):
print(f"Clothing: {self.name}, Price: {self.price}")
class Inventory:
def __init__(self):
self.items = []
def add_item(self, item):
self.items.append(item)
def show_inventory(self):
for item in self.items:
item.display()