Pokazać mechanizm MRO (Method Resolution Order) i bezpieczne użycie super() przy wielu klasach bazowych.
Gdy klasa dziedziczy po dwóch klasach, które mają wspólnego przodka, powstaje problem „diamentu" — niejednoznaczność, z której klasy pochodzi metoda.
Base
/ \
A B
\ /
C
Python rozwiązuje to przez liniaryzację C3 (Python 2.3+), która tworzy jednoznaczną listę przeszukiwania (MRO):
class Base: pass
class A(Base): pass
class B(Base): pass
class C(A, B): pass
print(C.mro())
# [<C>, <A>, <B>, <Base>, <object>]Metoda jest szukana od lewej do prawej w tej liście.
super() nie wywołuje „klasy nadrzędnej" — wywołuje następną klasę w MRO:
class LoggerMixin:
def describe(self) -> str:
return f"[LOG] {super().describe()}"
class TimestampMixin:
def describe(self) -> str:
return f"[TS] {super().describe()}"
class Base:
def describe(self) -> str:
return "base"
class Event(LoggerMixin, TimestampMixin, Base):
pass
print(Event().describe())
# [LOG] [TS] baseKażde super() przekazuje wywołanie dalej wzdłuż MRO — to umożliwia mixin-based composition.
Mixin to klasa bez własnego stanu (bez __init__), dostarczająca tylko zachowanie:
class JsonMixin:
def to_json(self) -> str:
import json
return json.dumps(self.__dict__)Diagram: diagrams/topic_08.png
Plik: examples/multiple_inheritance.py
class Event(LoggerMixin, TimestampMixin):
@classmethod
def describe_chain(cls) -> list[str]:
return [c.__name__ for c in cls.mro()]
@classmethod
def source(cls) -> str:
return cls.mro()[1].__name__ # pierwszy mixin po samej klasieprint(Event.describe_chain()) # ['Event', 'LoggerMixin', 'TimestampMixin', 'object']
print(Event.source()) # 'LoggerMixin'- Uruchom
examples/multiple_inheritance.py. - Dodaj trzeci mixin i przeanalizuj nowe MRO.
- Zmień kolejność klas bazowych — obserwuj jak zmienia się MRO.
- Zastosuj
super()w łańcuchudescribewszystkich mixinów. - Sprawdź co się stanie gdy dwa mixiny mają metodę o tej samej nazwie.
- Student rozumie MRO i potrafi go odczytać przez
ClassName.mro(). - Student potrafi bezpiecznie łączyć mixiny z klasą domenową.
- szablon:
exercises/tasks.py - przykładowe rozwiązanie:
exercises/solutions_08.py - testy:
exercises/test_solutions.py
Zadanie: zaimplementuj metodę source() zwracającą nazwę pierwszego mixinu w MRO.
- Co to jest MRO i jak działa algorytm C3?
- Dlaczego kolejność klas bazowych ma znaczenie?
- Jak
super()zachowuje się w wielodziedziczeniu? - Czym jest mixin i kiedy go stosować?
- Kiedy lepiej użyć kompozycji zamiast wielodziedziczenia?
- https://docs.python.org/3/reference/datamodel.html#mro
- https://www.python.org/download/releases/2.3/mro/
- L. Ramalho, Fluent Python, rozdz. „Multiple Inheritance and Method Resolution Order".
