Composition and mixins
Inheritance says "is a": a square is a shape. Composition says "has a": a car has an engine, stored as an attribute, and the car hands work to it. Prefer composition by default. Parts can be swapped at runtime or in tests, and a change to one part does not ripple through a hierarchy.
import json
class JsonMixin:
def to_json(self):
return json.dumps(vars(self))
class Point(JsonMixin):
def __init__(self, x, y):
self.x, self.y = x, y
class Engine:
def start(self):
return "vroom"
class Car:
def __init__(self, engine):
self.engine = engine
def start(self):
return self.engine.start()
print(Point(1, 2).to_json())
print(Car(Engine()).start())Mixins
A mixin is a small class that adds one capability and is never used alone. It has no __init__, relies only on what its host provides, and is listed first: class User(JsonMixin, Base). Mixins are where multiple inheritance stays simple, because each one adds methods without competing for state.
Your task
Finish ReprMixin, whose repr shows the class name and every instance attribute as keyword arguments, like Item(name='pen', price=2), and EqualityMixin, under which objects of the same class are equal when their attributes are. Change Notifier to receive a sender object in __init__, anything with send(text), instead of inheriting from EmailSender.
The explanation opens here once every check passes.