Classes and Objects
Definition
- A Class is a user-defined blueprint or prototype from which objects are created. Classes provide a means of bundling data and functionality together.
- Each class instance or Object can have attributes attached to it for maintaining its state. Objects can also have methods (defined by their class) for modifying their state.
- A class is like a blueprint while an instance is a copy of the class with actual values
- Classes are created by keyword class.
- Attributes are the variables that belong to a class.
- Attributes are always public and can be accessed using the dot (.) operator.
- State: It is represented by the attributes of an object. It also reflects the properties of an object.
- Behavior: It is represented by the methods of an object. It also reflects the response of an object to other objects.
- Identity: It gives a unique name to an object and enables one object to interact with other objects.
class Dog:
def __init__(self, name): # constructor
self.name = name # class attribute
def fun(self): # class method
print("My name is", self.name)
Rodger = Dog("Rogder") # Object instantiation
print(Rodger.name) # Rogder
Rodger.fun() # My name is Rogder
self
- Class methods must have an extra first parameter in the method definition. We do not give a value for this parameter when we call the method, Python provides it.
- If we have a method that takes no arguments, then we still have to have one argument (ie self)
- This is similar to this pointer in C++ and this reference in Java.
- When we call a method of this object as myobject.method(arg1, arg2), this is automatically converted by Python into MyClass.method(myobject, arg1, arg2)
__init__ ()
- The __init__ method is similar to constructors in C++ and Java. Constructors are used to initializing the object's state.
- It runs as soon as an object of a class is instantiated. The method is useful to do any initialization you want to do with your object.
- Constructor can be Default (no parameters except self) or Parameterized (multiple parameters)
__del__ ()
- The __del__ method is similar to destructors in C++ and Java. It is called when all references to the object have been deleted i.e when an object is garbage collected.
- In Python, destructors are not needed as much as in C++ because Python has a garbage collector that handles memory management automatically.
Class and instance variable
- Instance variables are variables whose value is assigned inside a constructor or method with self whereas class variables are variables whose value is assigned in the class.
class Dog:
animal = "dog"
def __init__(self, name): # set instance variable through constructor
self.name = name # class attribute
def fun(self): # class method
print("My name is", self.name)
def changeName(self, name):
self.name = name # change instance variable through class method
def __del__(self):
print("destructing object")
Rodger = Dog("Rogder") # Object instantiation
Rodger.fun() # My name is Rodger
Rodger.changeName("Sam")
Rodger.fun() # My name is Sam
Inheritance
- "object" class is root of all classes. So, even when a class is inheriting from no other class, it is actually inheriting from "object" class.
- If you forget to invoke the __init__() of the parent class then its instance variables would not be available to the child class.
- Private members of parent class are not accessible to the child class.
class Person(object): # parent class
def __init__(self, name):
self.name = name
def display(self):
print(self.name)
class Employee(Person): # child class
def __init__(self, name, designation):
self.designation = designation
Person.__init__(self, name) # invoking the __init__ of the parent class
a = Employee("abc", "Intern") # creation of an object variable or an instance
a.display() # calling a function of the class Person using its instance
Different forms of inheritance
There are 2 forms of Inheritance- Single inheritance: When a child class inherits from only one parent class.
- Multiple inheritance: When a child class inherits from multiple parent classes.
- Multilevel inheritance: When we have a child and grandchild relationship.
- Hierarchical inheritance: More than one derived classes are created from a single base.
- Hybrid inheritance: This form combines more than one form of inheritance.
'''
Single Inheritance
P1
|
C1
'''
class C1(P1): #
pass
'''
Multiple Inheritance
P1 P2
\ /
C1
'''
class C1(P1, P2)
pass
'''
Multilevel Inheritance
G1
|
P1
|
C1
'''
class P1(G1):
pass
class C1(P1):
pass
'''
Hierarchical Inheritance
P1
/ | \
C1 C2 C3
'''
class C1(P1):
pass
class C2(P1):
pass
class C3(P1):
pass
Encapsulation
Encapsulation is the idea of wrapping data
and the methods that work on data within one unit. This puts
restrictions on accessing variables and methods directly and can prevent
the accidental modification of data
example 🜜
Types of Members
- Protected Members: cannot be accessed outside the class but can be accessed from within the class and its subclasses. Prefix the name of the member by a single underscore "_"
- Private Members: are similar to protect except they should neither be accessed outside the class nor by any subclass. Prefix the name of the member by double underscore "__"
- Although the protected variable can be accessed out of the class as well as in the derived class(modified too in derived class), it is customary(convention not a rule) to not access the protected out the class body.
Polymorphism
Polymorphism means the same function name
(but different signatures) being used for different types.
''' Inbuilt Polymorphism of len() in Python '''
print(len("geeks")) # for string
print(len([10, 20, 30])) # for a list
''' User-defined Polymorphism '''
def add(x, y, z = 0):
return x + y+z
print(add(2, 3)) # 5
print(add(2, 3, 4)) # 9
''' User-defined Polymorphism with Class methods '''
class India():
def capital(self):
print("New Delhi")
class USA():
def capital(self):
print("Washington, D.C.")
obj_ind = India()
obj_usa = USA()
obj_ind.capital() # New Delhi
obj_usa.capital() # Washington, D.C.
''' Polymorphism with a Function and objects '''
def func(obj):
obj.capital()
func(obj_ind) # New Delhi
func(obj_usa) # Washington, D.C.
''' Polymorphism with Inheritance '''
class Bird:
def intro(self):
print("There are many types of birds.")
def flight(self):
print("Most of the birds can fly but some cannot.")
class sparrow(Bird):
def flight(self):
print("Sparrows can fly.")
class ostrich(Bird):
def flight(self):
print("Ostriches cannot fly.")
obj_bird = Bird()
obj_spr = sparrow()
obj_ost = ostrich()
obj_bird.intro() # There are many types of birds.
obj_bird.flight() # Most of the birds can fly but some cannot.
obj_spr.intro() # There are many types of birds.
obj_spr.flight() # Sparrows can fly.
obj_ost.intro() # There are many types of birds.
obj_ost.flight() # Ostriches cannot fly.
Class or Static Variables
- All objects of a class share class or static variables.
- An instance or non-static variables are different for different objects (every object has a copy)
class CSStudent:
stream = 'cse' # Class Variable
def __init__(self, name):
self.name = name # Instance Variable
a = CSStudent('abc')
b = CSStudent('bcd')
# class variable
CSStudent.stream == a.stream and a.stream == b.stream # True # all 3 are "cse"
# changing value of class variable for one of the objects
a.stream = "ece"
print(a.stream) # "ece"
print(b.stream) # "cse"
# changing value of class variable of all the objects at once
CSStudent.steam = "it"
print(a.stream) # "ece" - as it was explicitly changed earlier
print(b.stream) # "it"
Class v/s Static Methods
| Property | Class method | Static method |
| Definition | bound to the class and not the object of the class. | |
| Decorator | @classmethod | @staticmethod |
| Access/Modify Class state | Can do | Can't do |
| Any specific parameters | cls as first parameter | NA |
| General Usage | to create factory methods. Factory methods return class objects ( similar to a constructor ) for different use cases. | to create utility functions. |
class Variable:
def __init__(self, name):
self.name = name
@classmethod
def fromIncremented(cls, name, id):
return cls(fname + "_" + id)
@staticmethod
def isValid(name):
return name[0] != "_"
var1 = Person('abc')
var2 = Variable.fromIncremented('abc', 1)
print (Person.isValid("_123"))
Method Overloading and Overriding
- When the method of child class overrides the method of parent class on being called by the object of child class, it is known as Method Overriding.
- Method Overloading is the ability of a function or an operator to behave in different ways based on the parameters or the operands respectively.
Abstract Method and Abstract Class
- An Abstract method is a method that is declared, but contains no implementation.
- An Abstract class is a class that contains one or more abstract methods.
- An Abstract class may not be instantiated, and its abstract method must be implemented by the base class.
- Python provides a module named ABC which provides the base for defining Abstract Base Class (ABC).
from abc import ABC, abstractmethod
class Mother:
@abstractmethod
def absmethod(self):
pass
def defined(self):
print("this is a method that is defined in the ABC")
class Daughter(Mother):
def absmethod(self):
print("Abstract method implemented in the child class")