Object-Oriented Programming sounds intimidating until you realize it's really just... family trees and blueprints. Let's break down three concepts that trip up almost everyone at first: classes, inheritance, and MRO.
π§± What Is a Class?
A class is a blueprint. An object is the real thing built from that blueprint.
Think of a company that hires employees. Every employee has a name, age, and salary, and can work(). Instead of writing that logic separately for each person, you define it once:
class Employee:
def work(self):
print("Employee is working")
e1 = Employee()
e2 = Employee()
| Term | Meaning |
|---|---|
| Class | The design/template |
| Object | An actual instance created from that template |
Quick answer for interviews: "A class defines the attributes and methods its objects will have. An object is an instance of that class."
𧬠What Is Inheritance?
Inheritance lets a child class reuse the attributes and methods of a parent class β and add its own on top.
class Animal:
def eat(self):
print("Animal is eating")
class Dog(Animal):
def bark(self):
print("Dog is barking")
Animal
β
|
Dog
A Dog object can call both bark() and eat() β the second one comes free, inherited from Animal.
Why bother? Without it, you'd repeat the same eat()/sleep() code in every animal class. Inheritance = write once, reuse everywhere, specialize as needed.
π³ The 5 Types of Inheritance
| Type | Shape | Example |
|---|---|---|
| Single | A β B |
One parent, one child |
| Multilevel | A β B β C |
Grandparent β Parent β Child |
| Hierarchical |
A β B and A β C
|
One parent, many children |
| Multiple | A + B β C |
One child, many parents |
| Hybrid | Mix of the above | Combines two or more patterns |
A quick real-world flavor:
class Animal:
def eat(self): print("Eating")
class Machine:
def charge(self): print("Charging")
class Robot(Animal, Machine): # Multiple inheritance
pass
Robot can now both eat() and charge() β pulling from two separate parents.
π Overriding vs β Overloading (don't mix these up!)
| Concept | Meaning | Works in Python? |
|---|---|---|
| Overriding | Child redefines a method that already exists in the parent, giving it new behavior | β Yes |
| Overloading | Same method name, different parameter lists (like Java) | β Not directly |
Overriding example:
class Animal:
def sound(self): print("Animal makes sound")
class Dog(Animal):
def sound(self): print("Dog barks") # overrides parent
About overloading: Python doesn't support true overloading β defining add() twice just replaces the first version. Instead, we fake it with default arguments or *args:
class Calculator:
def add(self, a, b, c=0):
return a + b + c
π§ MRO: Method Resolution Order
MRO is just Python's rule for which class to check first when looking for a method β especially useful once multiple parents are involved.
Child
β
Parent
β
Grandparent
β
object
Python always starts the search at the object's own class and works upward. object sits at the very end β it's the ultimate base class every Python class inherits from, even implicitly.
Check it yourself:
print(Dog.mro())
# or
print(Dog.__mro__)
Where it really matters: multiple inheritance
class Bangalore:
def show(self):
print("Bangalore")
class Vizag(Bangalore):
def show(self):
print("Vizag")
class Hyderabad(Bangalore):
def show(self):
print("Hyderabad")
class Chennai(Hyderabad, Vizag):
pass
city = Chennai()
city.show()
print(Chennai.mro())
Hyderabad
[<class 'Chennai'>, <class 'Hyderabad'>, <class 'Vizag'>, <class 'Bangalore'>, <class 'object'>]
Chennai itself has no show(), so Python walks the MRO left to right: Chennai β Hyderabad β Vizagβ Bangalore β object. It hits Hyderabad first (since it's listed first in class Chennai(Hyderabad, Vizag)) and stops there β that's why the output is "Hyderabad", not "Vzag" or "Bangalore".
πͺ super() β jump to the next class in line
super() tells Python: "go to the next class in the MRO and use its version of this method." If you skip it, the parent's version simply never runs.
class Animal:
def speak(self):
print("Animal speaks")
class Dog(Animal):
def speak(self):
# super().speak()
print("Dog barks")
d = Dog()
d.speak()
Dog barks
Because super().speak() is commented out, Animal's speak() never gets called β Python only runs Dog's overridden version. Uncomment that line and you'd get both lines:
Animal speaks
Dog barks
π’ A Real-World Flavor
User roles in an e-commerce app:
User
/ \
Customer Seller β Admin
All roles share login()/logout() from User, while adding their own methods (buy_product(), add_product(), etc.).
Payment systems are a classic overriding example:
class Payment:
def pay(self): print("Processing payment")
class UPIPayment(Payment):
def pay(self): print("Processing UPI payment") # overridden
Mixins (common in frameworks) are where MRO quietly does its job:
class LoggingMixin:
def log(self): print("Logging")
class AuthMixin:
def authenticate(self): print("Authenticating")
class UserService(LoggingMixin, AuthMixin):
pass
π― Cheat-Sheet Answers
| Question | Short Answer |
|---|---|
| What is inheritance? | A child class reuses a parent's attributes/methods and can add or override behavior |
| Why use it? | Code reuse + specialization |
| What is overriding? | Child redefines a parent's method with its own implementation |
| Does Python support overloading? | No β use default args or *args instead |
| What is MRO? | The order Python searches classes for a method, especially with multiple inheritance |
Where does object sit in MRO? |
Always at the end β it's the base of everything |
| How to check MRO? |
ClassName.mro() or ClassName.__mro__
|
π‘ The Whole Topic, One Breath
A class is a blueprint that makes objects. A child class can use inheritance to reuse a parent's code β and if it redefines a method, that's overriding. Python skips true overloading in favor of default arguments. When multiple parents are involved, MRO decides the search order, always ending at
object. Andsuper()is your shortcut to the next class in that order.
Top comments (0)