๐ Inheritance in Python ๐๐๐จโ๐ฉโ๐งโ๐ฆ#
Inheritance is a core concept of object-oriented programming (OOP) that allows a class (the child class) to reuse, extend, or modify the behavior of another class (the parent class). This helps you avoid code repetition and maintain a clear, logical structure in your software.
Why Use Inheritance?#
Reusability
Child classes automatically inherit attributes and methods from the parent class.
Avoids duplicating code shared by multiple classes.
Extensibility
Children can add or modify functionality while preserving shared behavior from the parent.
Organizational Clarity
Logical hierarchy mirrors real-world or conceptual relationships (e.g.,
Car
is a type ofVehicle
).
Basic Example of Single Inheritance#
class Vehicle:
def __init__(self, make, model):
self.make = make
self.model = model
def start_engine(self):
print(f"{self.make} {self.model} engine started!")
class Car(Vehicle):
def __init__(self, make, model, doors):
# Call parent constructor using super()
super().__init__(make, model)
self.doors = doors
def open_trunk(self):
print(f"{self.make} {self.model} trunk opened.")
# Creating instances
my_car = Car("Toyota", "Corolla", 4)
my_car.start_engine() # Inherited from Vehicle
my_car.open_trunk() # Defined in Car
Toyota Corolla engine started!
Toyota Corolla trunk opened.
Key Points
- `Car` inherits all attributes and methods from `Vehicle` (like `start_engine`).
- `super().init()` calls the parent class constructor.
- `Car` adds new functionality: `open_trunk`.
Overriding Methods#
If the child class defines a method with the same name as a method in the parent class, it overrides that method:
class Vehicle:
def start_engine(self):
print("Vehicle's engine started (generic).")
class Car(Vehicle):
def start_engine(self):
print("Car's engine started (car-specific).")
my_car = Car()
my_car.start_engine() # "Car's engine started (car-specific)."
Car's engine started (car-specific).
Using super()
in an Overridden Method#
Sometimes you still want to call the original parent method, then add extra steps:
class Car(Vehicle):
def start_engine(self):
super().start_engine()
print("Performing additional car checks...")
my_car = Car()
my_car.start_engine()
Vehicle's engine started (generic).
Performing additional car checks...
Practical Examples#
Shape Hierarchy (Geometry)
class Shape:
def area(self):
raise NotImplementedError("Subclasses must implement this method.")
class Circle(Shape):
def __init__(self, radius):
self.radius = radius
def area(self):
return 3.14159 * (self.radius**2)
my_circle = Circle(5)
print(my_circle.area()) # 78.53975
78.53975
Circle
overridesarea()
fromShape
.Enforces a pattern where every shape must implement its own
area()
.
User Permissions (Web/App)
class User:
def __init__(self, username):
self.username = username
def can_access(self, resource):
# Basic users might have minimal access
return resource in ["public"]
class Admin(User):
def can_access(self, resource):
# Admins can access everything
return True
user = User("john_doe")
admin = Admin("admin_user")
print(user.can_access("public")) # True
print(user.can_access("private")) # False
print(admin.can_access("private")) # True (overridden behavior)
True
False
True
Composition vs. Inheritance#
Composition: Instead of inheriting, you have one class hold an instance of another.
class Engine:
def start(self):
print("Engine started.")
class Vehicle:
def __init__(self):
self.engine = Engine()
def start_engine(self):
self.engine.start()
When something is not strictly a specialized form of a parent class, composition may be more natural.
When to Use Inheritance
IS-A Relationship:
Car
is aVehicle
.
Shared or Extended Behavior: Common logic in the parent, specialized in the child.
6. Best Practices#
Use
super()
Ensures correct initialization of parent class attributes.
Helps maintain readability in child methods.
Keep Hierarchies Simple
Deep, complex inheritance chains can be difficult to understand and maintain.
Override Responsibly
Only override methods if you need to provide different or enhanced behavior.
Enforce Consistency
If your parent class has certain expectations (e.g., a
move()
method), ensure child classes follow the same interface.