Python Inheritance & Data Model
Inheritance existing class ko extend karne ka tool hai, while Python data model special methods ke through objects ko built-in language behavior ke saath integrate karta hai. Is chapter me inheritance ko responsibly use karna, polymorphism samajhna aur Pythonic objects design karna seekhenge.
What is inheritance?
Inheritance me one class another class ke attributes and methods inherit kar sakti hai. Parent/base class common behavior define karti hai, and child/subclass us behavior ko reuse ya extend kar sakti hai.
class User:
def __init__(self, name):
self.name = name
def describe(self):
return f"User: {self.name}"
class Student(User):
pass
student = Student("Aman")
print(student.describe())Student(User) ka meaning hai Student, User se inherit karta hai. Student ne describe() khud define nahi kiya, phir bhi inherited method use kar sakta hai.
Use inheritance for a real is-a relationship
Inheritance tab useful hota hai jab subclass genuinely parent ka specialized version ho. Example: Student is a User. Lekin Car is an Engine nahi hai; Car has an Engine, so composition better fit hai.
Call parent behavior with super()
class User:
def __init__(self, name):
self.name = name
class Student(User):
def __init__(self, name, course):
super().__init__(name)
self.course = course
student = Student("Riya", "Python")
print(student.name, student.course)super() parent class ko hard-code kiye bina next implementation ko access karta hai. Multiple inheritance me ye method resolution order ke saath cooperate karta hai.
Method overriding
Subclass inherited method ko same name ke saath redefine kar sakti hai.
class User:
def role(self):
return "user"
class Student(User):
def role(self):
return "student"
print(User().role())
print(Student().role())Method override karte waqt caller ke expected contract ko preserve karna important hai.
Extend instead of fully replacing
class User:
def summary(self):
return "BrounStack user"
class Student(User):
def summary(self):
base = super().summary()
return f"{base} · student"
print(Student().summary())Child method parent result ko use karke additional behavior add kar sakta hai.
Polymorphism
Polymorphism means same operation different object types par meaningful behavior produce kar sakti hai.
class EmailNotification:
def send(self):
return "Email sent"
class SmsNotification:
def send(self):
return "SMS sent"
def notify(channel):
print(channel.send())
notify(EmailNotification())
notify(SmsNotification())Notice: EmailNotification and SmsNotification ko common parent class ki zaroorat nahi. Python me compatible behavior often enough hota hai.
Duck typing
Python frequently object ke exact class se zyada uske supported operations par focus karta hai. Agar object required method/protocol support karta hai, code use kar sakta hai.
isinstance() and issubclass()
class User:
pass
class Student(User):
pass
student = Student()
print(isinstance(student, Student))
print(isinstance(student, User))
print(issubclass(Student, User))Runtime type checks kabhi useful hain, but excessive isinstance() chains polymorphic design ko defeat kar sakte hain.
Multiple inheritance — beginner view
Python class multiple base classes se inherit kar sakti hai. Powerful hai, but design complexity increase hoti hai.
class Printable:
def print_info(self):
return "Printable"
class Savable:
def save(self):
return "Saved"
class Report(Printable, Savable):
pass
report = Report()
print(report.print_info())
print(report.save())Small mixin-like behaviors useful ho sakte hain, but deep/complicated inheritance trees beginner projects me avoid karo.
Method Resolution Order (MRO)
Multiple inheritance me same method multiple bases me ho sakta hai. Python deterministic MRO use karta hai to decide lookup order.
class A:
def show(self):
return "A"
class B(A):
pass
class C(A):
def show(self):
return "C"
class D(B, C):
pass
print(D().show())
print([cls.__name__ for cls in D.mro()])super() simply “my parent” nahi; it follows the MRO. Isi reason se cooperative inheritance me consistent super() usage important hota hai.
What is the Python data model?
Python data model defines how objects participate in language operations. Special methods, often “dunder” methods, built-in syntax aur functions ke hooks provide karte hain.
__str__— human-friendly string.__repr__— developer/debug representation.__len__—len(obj).__eq__—obj1 == obj2.__lt__— less-than comparison.__add__—obj1 + obj2.__iter__— iteration protocol; Chapter 18 me detail.
__str__ and __repr__
class Student:
def __init__(self, name, score):
self.name = name
self.score = score
def __str__(self):
return f"{self.name}: {self.score}"
def __repr__(self):
return f"Student(name={self.name!r}, score={self.score!r})"
student = Student("Aman", 88)
print(student)
print(repr(student))__repr__ ideally unambiguous/debug-friendly hona chahiye. !r nested values ka repr use karta hai.
Make an object work with len()
class Course:
def __init__(self, students):
self.students = list(students)
def __len__(self):
return len(self.students)
course = Course(["Aman", "Riya", "Kabir"])
print(len(course))Special method tab add karo jab operation object ke domain me naturally meaningful ho.
Custom equality with __eq__
class Student:
def __init__(self, student_id, name):
self.student_id = student_id
self.name = name
def __eq__(self, other):
if not isinstance(other, Student):
return NotImplemented
return self.student_id == other.student_id
print(Student(1, "Aman") == Student(1, "Aman Verma"))Unsupported type ke comparison me NotImplemented return karna Python ko reflected/alternative comparison handling ka chance deta hai.
Operator overloading
class Score:
def __init__(self, value):
self.value = value
def __add__(self, other):
if not isinstance(other, Score):
return NotImplemented
return Score(self.value + other.value)
def __repr__(self):
return f"Score({self.value})"
print(Score(40) + Score(35))Operators ko surprising meaning mat do. + tab overload karo jab addition/combination domain me natural ho.
Equality and hashing caution
Hashable objects sets/dict keys me use ho sakte hain. Custom mutable objects ke liye __eq__ aur __hash__ relationship carefully design karna padta hai. Beginner rule: mutable identity/value objects ko dict key banane ki rush mat karo.
Properties still work with inheritance
Chapter 16 ki properties subclasses me inherit hoti hain. Validation behavior reuse ho sakta hai, but subclass ko parent invariants silently break nahi karne chahiye.
Dataclasses reduce boilerplate
@dataclass data-focused classes ke liye generated __init__, __repr__ and equality behavior provide kar sakta hai.
from dataclasses import dataclass
@dataclass
class Student:
name: str
score: float
first = Student("Aman", 88)
second = Student("Aman", 88)
print(first)
print(first == second)Type annotations metadata/tooling ko help karti hain; normal Python runtime automatically every assignment ko enforce nahi karta.
Frozen dataclasses
from dataclasses import dataclass
@dataclass(frozen=True)
class CourseCode:
value: str
code = CourseCode("PY101")
print(code)frozen=True normal field reassignment ko block karta hai and immutable-style value objects me useful ho sakta hai. Ye deep immutability ka universal guarantee nahi.
Inheritance vs composition
- Use inheritance for a stable, meaningful is-a relationship.
- Use composition for has-a relationships and swappable collaborators.
- Prefer simple designs; deep inheritance trees understand/test karna harder hote hain.
- Polymorphism ko exact class hierarchy se unnecessarily couple mat karo.
Abstract base classes — preview
abc module explicit interfaces/contracts define karne me help kar sakta hai, but beginner projects me duck typing often sufficient hota hai.
from abc import ABC, abstractmethod
class Exporter(ABC):
@abstractmethod
def export(self):
passCommon beginner mistakes
- Sirf code reuse ke liye inheritance force karna.
- Deep inheritance hierarchy banana without clear domain reason.
- Subclass me parent initializer required hote hue
super().__init__()forget karna. - Override method ka expected behavior/return contract completely break karna.
super()ko always direct parent call samajhna.- Multiple inheritance use karke MRO ignore karna.
- Every helper ko magic/dunder method banana.
__repr__me secrets or sensitive data print karna.__eq__implement karke unsupported types ko incorrectly compare karna.- Dataclass ko business logic/design ka replacement samajhna.
Beginner best practices
- Inheritance hierarchy shallow rakho.
- Composition ko strong alternative ke roop me consider karo.
super()consistently use karo in cooperative class designs.- Special methods tab implement karo jab built-in operation naturally meaningful ho.
- Readable
__repr__debugging improve karta hai. - Domain identity/value semantics decide karke hi custom equality define karo.
- Data-focused records ke liye dataclass consider karo.
- Public interface simple and predictable rakho.
Chapter checklist
- Base class aur subclass ka relationship clear hai?
super()se parent/cooperative behavior call kar sakte ho?- Method overriding samajh aaya?
- Polymorphism aur duck typing ka difference/use clear hai?
isinstance(),issubclass()aur MRO ka basic idea hai?__str__,__repr__,__len__,__eq__ka role clear hai?- Inheritance vs composition choose karne ka basic rule samajh aaya?
@dataclasska purpose samajh aaya?
Practice Task — Learning Membership System
BrounStack Playground me inheritance + data model based mini system banao.
Userbase class banao withnameandemail.Studentsubclass banao andcourseadd karo.Instructorsubclass banao andsubjectadd karo.- Dono subclasses me
role()override karo. - Constructors me
super().__init__()use karo. - List me mixed Student/Instructor objects store karo.
- Loop me same
role()call karke polymorphism show karo. __str__readable output ke liye implement karo.__repr__debugging representation add karo.- Student objects ke liye sensible equality rule decide karo.
- One small composed object add karo, e.g.
ProfileorAddress. isinstance()ka one useful check add karo.- One small dataclass value object banao, e.g.
CourseCode. - Explain in comments ki kaha inheritance use ki aur kaha composition.