OOPs
1. Classes, Instances, and State
Section titled “1. Classes, Instances, and State”-
Concept: A user-defined blueprint (Class) used to create specific data objects (Instances).
-
Methods & Syntax:
class ClassName:Defines the blueprint.__init__(self, args): The constructor method. Automatically initializes the object’s initial state.selfrefers to the specific instance being created.Class.variable: A class-level attribute shared across all instances.self.variable: An instance-level attribute unique to that specific object.
Program:
class Employee:"""Blueprint for Cloud Team members."""empCount = 0 # Class variable (shared)def __init__(self, role, salary):self.role = role # Instance variable (unique)self.salary = salaryEmployee.empCount += 1def displayEmployee(self):print(f"Role: {self.role}, Salary: {self.salary}")# Creating Instancesemp1 = Employee("Cloud Intern", 200)emp2 = Employee("Cloud Manager", 5000)emp1.displayEmployee()emp2.displayEmployee()print(f"Total Employees: {Employee.empCount}")# Output:# Role: Cloud Intern, Salary: 200# Role: Cloud Manager, Salary: 5000# Total Employees: 2
2. Dynamic Attribute Modification
Section titled “2. Dynamic Attribute Modification”-
Concept: Python allows you to dynamically add, read, modify, or delete attributes of an object after it has been instantiated.
-
Methods & Syntax:
hasattr(obj, 'name'): ReturnsTrueif the attribute exists.getattr(obj, 'name'): Returns the value of the attribute.setattr(obj, 'name', value): Sets or creates the attribute with the given value.delattr(obj, 'name'): Deletes the attribute.
Program:
# Continuing with emp1 from abovesetattr(emp1, 'git_commits', 15) # Dynamically add an attributeif hasattr(emp1, 'git_commits'):print(getattr(emp1, 'git_commits')) # Outputs: 15delattr(emp1, 'git_commits') # Deletes the attribute# getattr(emp1, 'git_commits') # Would now raise AttributeError
3. Inheritance & Method Resolution Order (MRO)
Section titled “3. Inheritance & Method Resolution Order (MRO)”-
Concept: A Child class extracts and reuses methods/properties from one or more Parent (Base) classes.
-
Methods & Syntax:
class Child(Base1, Base2):: Multiple inheritance syntax.super().method(): Calls a method from the immediate parent class.- MRO Logic: Bottom-to-Top, Left-to-Right. Python checks the Child first, then
Base1(Left), thenBase2(Right).
Program:
class Base1:def execute(self):print("Executing Base1 script")class Base2:def deploy(self):print("Deploying from Base2")class Child(Base1, Base2):def execute(self):print("Executing Child script")super().execute() # Triggers Base1.execute due to MRO (Left parent)c = Child()c.execute()# Output:# Executing Child script# Executing Base1 scriptc.deploy()# Output: Deploying from Base2
4. “Private” Variables & Name Mangling
Section titled “4. “Private” Variables & Name Mangling”-
Concept: Python does not have strict private variables. It uses naming conventions to protect data from accidental modification.
-
Methods & Syntax:
_variable: (Single underscore) Convention indicating a non-public implementation detail. Do not touch.__variable: (Double underscore) Triggers Name Mangling. The interpreter renames it to_ClassName__variableto prevent subclass naming collisions.
Program:
class ServerCounter:__secretCount = 0 # Mangled variabledef count(self):self.__secretCount += 1print(self.__secretCount)counter = ServerCounter()counter.count() # Output: 1counter.count() # Output: 2# print(counter.__secretCount) # Raises AttributeErrorprint(counter._ServerCounter__secretCount) # Output: 2 (Bypassing the mangle)
5. Magic (Dunder) Methods & Operator Overloading
Section titled “5. Magic (Dunder) Methods & Operator Overloading”-
Concept: Special internal methods enclosed in double underscores (
__method__) that dictate how standard Python operators (+, ,print) interact with your custom objects. -
Methods & Syntax:
__str__(self): Dictates what is printed when you callprint(object).__add__(self, other): Dictates what happens when you use the+operator between two instances.
Program:
class Vector:def __init__(self, a, b):self.a = aself.b = bdef __str__(self):# Overloads how the object represents itself as a stringreturn f'Vector ({self.a}, {self.b})'def __add__(self, other):# Overloads the '+' operator logicreturn Vector(self.a + other.a, self.b + other.b)v1 = Vector(2, 10)v2 = Vector(5, -2)# Implicitly calls v1.__add__(v2), and then print() implicitly calls __str__print(v1 + v2)# Output:# Vector (7, 8)