Python Composition
definitions
python
composition
oop
Composition is a way of building a class out of other objects: an object of one class holds an object of another class as one of its attributes. This forms a has-a relationship (e.g. a Car has-a Engine) — as opposed to inheritance’s is-a relationship (e.g. a SportsCar is-a Car).
Basic pattern
class Car():
def __init__(self, engine: Engine) -> None:
self._engine = engine # Car has-a engine
def start(self):
self._engine.start()
The outer object (Car) doesn’t need to know how the inner object (Engine) works internally — it just calls the inner object’s public methods. This keeps each class focused on a single responsibility.
Worked example: Car/Engine
class Engine:
def __init__(self, horsepower, fuel_type="gasoline"):
self.horsepower = horsepower
self.fuel_type = fuel_type
self.running = False
def start(self):
if not self.running:
self.running = True
print(f"{self.fuel_type.capitalize()} engine with {self.horsepower} HP started.")
else:
print("Engine is already running.")
def stop(self):
if self.running:
self.running = False
print("Engine stopped.")
else:
print("Engine is already off.")
class Car:
def __init__(self, make, model, engine: Engine):
self.make = make
self.model = model
self.engine = engine
def start(self):
print(f"Starting the {self.make} {self.model}...")
self.engine.start()
def stop(self):
print(f"Stopping the {self.make} {self.model}...")
self.engine.stop()
def swap_engine(self, new_engine: Engine):
if self.engine.running:
print("Stopping current engine before swap...")
self.engine.stop()
print(f"Swapping engine in {self.make} {self.model}...")
self.engine = new_engine
print("New engine installed!")
>>> small_engine = Engine(150, "gasoline")
>>> car = Car("Toyota", "Corolla", small_engine)
>>> car.start()
Starting the Toyota Corolla...
Gasoline engine with 150 HP started.
>>> big_engine = Engine(300, "diesel")
>>> car.swap_engine(big_engine) # safely stops the old engine first, if running
Composition vs. inheritance
- Use composition (“has-a”) when an object is made up of other objects, or uses another object to do part of its job.
- Use inheritance (“is-a”) when a new class is a more specific version of an existing class.
Composition tends to be more flexible: a composed attribute can be freely swapped for any object supporting the same interface (see duck typing), without needing any shared base class.