Inheritance vs π§© Composition in Object-Oriented Programming
Design Better Python Classes with These Two Techniques

Tech lead exploring Generative AI & ML π | Python, JS, React | Aviation meets Innovation β | Writing what I learn. Learning what I build.
When designing software systems using Object-Oriented Programming (OOP), two powerful techniques to organize and reuse code are inheritance and composition. While both achieve code reuse, they differ significantly in how they model relationships between objects.
Understanding the difference is crucial for building clean, maintainable, and scalable software. Letβs dive into their definitions, use-cases, and differences.
π What is Inheritance?
Inheritance is when one class (the child/subclass) derives from another class (the parent/base class) and inherits its attributes and methods.
π Relationship: "Is-a"
If Dog inherits from Animal, then a Dog is an Animal.
β Example:
class Animal:
def speak(self):
print("Animal speaks")
class Dog(Animal):
def speak(self):
print("Dog barks")
d = Dog()
d.speak()
π‘ Output:
Dog barks
Here, Dog overrides the speak() method of Animal, demonstrating method overriding.
π§© What is Composition?
Composition means that one class contains an instance of another class and delegates work to it. Instead of inheriting, it uses the capabilities of other classes by composing them together.
π Relationship: "Has-a"
If Car contains an Engine, then a Car has an Engine.
β Example:
class Engine:
def start(self):
print("Engine starts")
class Car:
def __init__(self):
self.engine = Engine()
def start(self):
self.engine.start()
c = Car()
c.start()
π‘ Output:
Engine starts
π Inheritance vs Composition: Head-to-Head
| Feature | Inheritance | Composition |
| Definition | Derives a class from another | Combines behaviors by containing other objects |
| Relationship Type | "Is-a" | "Has-a" |
| Coupling | Tight coupling to base class | Loose coupling, flexible components |
| Code Reuse | Through class hierarchy | Through object collaboration |
| Flexibility | Less flexible; base changes ripple to children | More flexible; easier to swap or modify parts |
| Best Used When | Objects share strong common behavior | You want to delegate behavior or plug in reusable components |
| Example Keyword | class B(A): | self.obj = SomeOtherClass() |
β οΈ Real-World Scenarios
𧬠Inheritance:
Use when there's a clear type hierarchy.
class Person:
def get_id(self):
return "Generic ID"
class Employee(Person):
def get_id(self):
return "Employee ID"
π§© Composition:
Use when you want to plug in behaviors or combine functionalities.
class Logger:
def log(self, msg):
print(f"Log: {msg}")
class Service:
def __init__(self):
self.logger = Logger()
def run(self):
self.logger.log("Service started")
π§ When to Use Which?
| Use Inheritance When | Use Composition When |
| There's a clear "is-a" relationship | You want flexibility and modularity |
| You want to extend a base classβs functionality | You want to combine behavior from different classes |
| Code reuse through polymorphism makes sense | You want to favor delegation over tight coupling |
π Conclusion
Both inheritance and composition are foundational to OOP, but serve different purposes.
Use inheritance for strongly related types that share behavior.
Use composition when building modular, flexible systems that need to evolve easily.
In modern software design, especially in large systems, composition is often preferred β summarized by the principle:
βFavor composition over inheritance.β
