Inheritance vs Composition in Python: Key Differences and Usage
inheritance means creating a new class based on an existing class to reuse or extend its behavior, while composition means building classes by including instances of other classes to achieve functionality. Inheritance forms an "is-a" relationship, and composition forms a "has-a" relationship.Quick Comparison
Here is a quick side-by-side comparison of inheritance and composition in Python.
| Factor | Inheritance | Composition |
|---|---|---|
| Relationship Type | "is-a" (e.g., Dog is an Animal) | "has-a" (e.g., Car has an Engine) |
| Code Reuse | Reuses parent class methods and attributes | Reuses functionality by including objects |
| Flexibility | Less flexible, tightly coupled | More flexible, loosely coupled |
| Change Impact | Changes in parent affect all children | Changes in components affect only composed objects |
| Use Case | When classes share common behavior | When classes combine different behaviors |
| Design Principle | Follows class hierarchy | Follows object collaboration |
Key Differences
Inheritance creates a new class by extending an existing class, inheriting its methods and properties. This means the child class automatically has the behavior of the parent class and can override or add new features. It models an "is-a" relationship, like a Dog class inheriting from an Animal class.
Composition builds complex objects by combining simpler objects. Instead of inheriting, a class contains instances of other classes and delegates tasks to them. This models a "has-a" relationship, like a Car class having an Engine object inside it.
Inheritance can lead to tight coupling and fragile code if the parent class changes unexpectedly. Composition encourages loose coupling and better modularity, making it easier to change parts without affecting the whole system.
Code Comparison
Here is an example using inheritance to model a Dog that can bark and move.
class Animal: def move(self): return "Moving" class Dog(Animal): def bark(self): return "Woof!" my_dog = Dog() print(my_dog.move()) print(my_dog.bark())
Composition Equivalent
Here is the same example using composition, where Dog has an Animal object to reuse its move method.
class Animal: def move(self): return "Moving" class Dog: def __init__(self): self.animal = Animal() def bark(self): return "Woof!" def move(self): return self.animal.move() my_dog = Dog() print(my_dog.move()) print(my_dog.bark())
When to Use Which
Choose inheritance when you have a clear hierarchical relationship and want to reuse or extend behavior from a base class, such as different types of animals sharing common traits. Use composition when you want more flexibility by combining simple objects to build complex functionality, especially when behaviors can change at runtime or when you want to avoid tight coupling.
In general, prefer composition for better modularity and maintainability, and use inheritance when it naturally fits the problem domain.