5.8. OOP Inheritance Patterns¶
no inheritance
single inheritance
multilevel inheritance
multiple inheritance (mixin classes)
- single inheritance¶
One class inherits from one other class. Has one parent.
- multilevel inheritance¶
One class inherits from other class, and yet another class inherits from it. This creates hierarchical structure.
- multiple inheritance¶
- mixin classes¶
One class derives from several other classes at once.
5.8.1. No Inheritance¶
>>> class Parent:
... pass
>>>
>>>
>>> class Child:
... pass
5.8.2. Single Inheritance¶
>>> class Parent:
... pass
>>>
>>>
>>> class Child(Parent):
... pass
5.8.3. Multilevel Inheritance¶
>>> class Grandparent:
... pass
>>>
>>>
>>> class Parent(Grandparent):
... pass
>>>
>>>
>>> class Child(Parent):
... pass
5.8.4. Multiple Inheritance¶
Mother
andFather
are Mixin Classes
>>> class Mother:
... pass
>>>
>>>
>>> class Father:
... pass
>>>
>>>
>>> class Child(Mother, Father):
... pass
5.8.5. Composition¶
Static version:
>>> class Mother:
... pass
>>>
>>> class Father:
... pass
>>>
>>> class Child:
... mother = Mother
... father = Father
Dynamic version:
>>> class Mother:
... pass
>>>
>>> class Father:
... pass
>>>
>>>
>>> class Child:
... mother: Mother
... father: Father
...
... def __init__(self, mother=Mother(), father=Father()):
... self.mother = mother
... self.father = father
5.8.6. Aggregation¶
Static version:
>>> class Mother:
... pass
>>>
>>> class Father:
... pass
>>>
>>> class Child:
... parents = [Father, Mother]
Dynamic version:
>>> class Mother:
... pass
>>>
>>> class Father:
... pass
>>>
>>>
>>> class Child:
... parents: list[Mother|Father]
...
... def __init__(self, mother=Mother(), father=Father()):
... self.parents = []
... self.parents.append(mother)
... self.parents.append(father)
5.8.7. Why?¶
>>> class Mother:
... pass
>>>
>>> class Father:
... pass
>>>
>>>
>>> class Child:
... mother: Mother
... father: Father
...
... def __init__(self, mother=Mother(), father=Father()):
... self.mother = mother
... self.father = father
>>> class StepFather:
... pass
>>>
>>> me = Child(father=StepFather())
5.8.8. Use Case - 0x01¶
>>> class Mother:
... def say_hello(self):
... pass
>>>
>>> class Father:
... def say_hello(self):
... pass
>>>
>>>
>>> class Child:
... father: Father
... mother: Mother
...
... def __init__(self, mother: Mother = Mother(), father: Father = Father()):
... self.mother = mother
... self.father = father
...
... def father_say_hello(self):
... self.father.say_hello()
...
... def mother_say_hello(self):
... self.mother.say_hello()
5.8.9. Use Case - 0x02¶
>>> from json import JSONEncoder, JSONDecoder
>>>
>>>
>>> class User:
... json_encoder: JSONEncoder
... json_decoder: JSONDecoder
...
... def __init__(self,
... json_encoder: JSONEncoder = JSONEncoder(),
... json_decoder: JSONDecoder = JSONDecoder(),
... ) -> None:
... self.json_encoder = json_encoder
... self.json_decoder = json_decoder
...
... def json_encode(self, data):
... self.json_encoder.encode(data)
...
... def json_decoder(self, data):
... self.json_decoder.decode(data)
5.8.10. Use Case - 0x03¶
>>> from datetime import date
>>> import json
>>> DATA = {'firstname': 'Mark', 'lastname': 'Watney'}
>>>
>>> json.dumps(DATA)
'{"firstname": "Mark", "lastname": "Watney"}'
>>> DATA = {'firstname': 'Mark', 'lastname': 'Watney', 'birthday': date(1969, 7, 21)}
>>>
>>> json.dumps(DATA)
Traceback (most recent call last):
TypeError: Object of type date is not JSON serializable
>>> class Encoder(json.JSONEncoder):
... def default(self, x):
... if isinstance(x, date):
... return x.isoformat()
...
>>>
>>> DATA = {'firstname': 'Mark', 'lastname': 'Watney', 'birthday': date(1969, 7, 21)}
>>>
>>> json.dumps(DATA, cls=Encoder)
'{"firstname": "Mark", "lastname": "Watney", "birthday": "1969-07-21"}'
5.8.11. Further Reading¶
5.8.12. Assignments¶
"""
* Assignment: OOP InheritancePatterns NoInheritance
* Complexity: easy
* Lines of code: 8 lines
* Time: 3 min
English:
1. Create classes `MarsMission`, `Habitat`, `Rocket`, `Astronaut`
2. Do not use inheritance
3. Assignment demonstrates syntax, so do not add any attributes and methods
4. Run doctests - all must succeed
Polish:
1. Stwórz klasy `MarsMission`, `Habitat`, `Rocket`, `Astronaut`
2. Nie używaj dziedziczenia
3. Zadanie demonstruje składnię, nie dodawaj żadnych atrybutów i metod
4. Uruchom doctesty - wszystkie muszą się powieść
Tests:
>>> import sys; sys.tracebacklimit = 0
>>> from inspect import isclass
>>> assert isclass(Habitat)
>>> assert isclass(Astronaut)
>>> assert isclass(Rocket)
>>> assert isclass(MarsMission)
"""
"""
* Assignment: OOP InheritancePatterns Multilevel
* Complexity: easy
* Lines of code: 8 lines
* Time: 3 min
English:
1. Create class `MarsMission` from classes `Habitat`, `Rocket`, `Astronaut`
2. Use multilevel inheritance
3. Assignment demonstrates syntax, so do not add any attributes and methods
4. Run doctests - all must succeed
Polish:
1. Stwórz klasę `MarsMission` z klas `Habitat`, `Rocket`, `Astronaut`
2. Użyj wielopoziomowego dziedziczenia
3. Zadanie demonstruje składnię, nie dodawaj żadnych atrybutów i metod
4. Uruchom doctesty - wszystkie muszą się powieść
Tests:
>>> import sys; sys.tracebacklimit = 0
>>> from inspect import isclass
>>> assert isclass(Habitat)
>>> assert isclass(Astronaut)
>>> assert isclass(Rocket)
>>> assert isclass(MarsMission)
>>> assert issubclass(MarsMission, Habitat)
>>> assert issubclass(MarsMission, Astronaut)
>>> assert issubclass(MarsMission, Rocket)
>>> assert len(Habitat.__subclasses__()) == 1
>>> assert len(Astronaut.__subclasses__()) == 1
>>> assert len(Rocket.__subclasses__()) == 1
>>> assert len(MarsMission.__subclasses__()) == 0
"""
"""
* Assignment: OOP InheritancePatterns Composition
* Complexity: easy
* Lines of code: 10 lines
* Time: 3 min
English:
1. Create class `MarsMission` from classes `Habitat`, `Rocket`, `Astronaut`
2. Use composition
3. Assignment demonstrates syntax, so do not add any attributes and methods (only type annotations)
4. Run doctests - all must succeed
Polish:
1. Stwórz klasę `MarsMission` z klas `Habitat`, `Rocket`, `Astronaut`
2. Użyj kompozycji
3. Zadanie demonstruje składnię, nie dodawaj żadnych atrybutów i metod (tylko anotacje typów)
4. Uruchom doctesty - wszystkie muszą się powieść
Tests:
>>> import sys; sys.tracebacklimit = 0
>>> from inspect import isclass
>>> assert isclass(Habitat)
>>> assert isclass(Astronaut)
>>> assert isclass(Rocket)
>>> assert isclass(MarsMission)
>>> assert MarsMission.__annotations__['habitat'] is Habitat
>>> assert MarsMission.__annotations__['astronaut'] is Astronaut
>>> assert MarsMission.__annotations__['rocket'] is Rocket
"""
"""
* Assignment: OOP InheritancePatterns Multiple
* Complexity: easy
* Lines of code: 8 lines
* Time: 3 min
English:
1. Create class `MarsMission` from classes `Habitat`, `Rocket`, `Astronaut`
2. Use mixins classes
3. You can modify given classes
4. Assignment demonstrates syntax, so do not add any attributes and methods
5. Run doctests - all must succeed
Polish:
1. Stwórz klasę `MarsMission` z klas `Habitat`, `Rocket`, `Astronaut`
2. Użyj klas domieszkowych (mixin)
3. Możesz modyfikować dane klasy
4. Zadanie demonstruje składnię, nie dodawaj żadnych atrybutów i metod
5. Uruchom doctesty - wszystkie muszą się powieść
Tests:
>>> import sys; sys.tracebacklimit = 0
>>> from inspect import isclass
>>> assert isclass(Habitat)
>>> assert isclass(Astronaut)
>>> assert isclass(Rocket)
>>> assert isclass(MarsMission)
>>> assert issubclass(MarsMission, Habitat)
>>> assert issubclass(MarsMission, Astronaut)
>>> assert issubclass(MarsMission, Rocket)
>>> assert len(Habitat.__subclasses__()) == 1
>>> assert len(Astronaut.__subclasses__()) == 1
>>> assert len(Rocket.__subclasses__()) == 1
>>> assert len(MarsMission.__subclasses__()) == 0
"""