9.6. OOP Inheritance¶
9.6.1. Rationale¶
Child inherits all fields and methods from parent
Used to avoid code duplication
9.6.2. Syntax¶
>>> class Parent:
... def say_hello(self):
... return 'Hello'
>>>
>>> class Child(Parent):
... pass
>>>
>>>
>>> obj = Child()
>>> obj.say_hello()
'Hello'
9.6.3. Simple Inheritance¶
>>> class Engineer:
... def __init__(self, firstname, lastname):
... self.firstname = firstname
... self.lastname = lastname
>>>
>>> class Astronaut(Engineer):
... pass
>>>
>>> class Cosmonaut(Engineer):
... pass
>>>
>>>
>>> mark = Astronaut('Mark', 'Watney')
>>> ivan = Cosmonaut('Ivan', 'Ivanovic')
9.6.4. Multilevel Inheritance¶
>>> class Engineer:
... pass
>>>
>>> class Pilot(Engineer):
... pass
>>>
>>> class Astronaut(Pilot):
... pass
>>>
>>>
>>> watney = Astronaut()
>>> type(watney)
<class 'Astronaut'>
>>> isinstance(watney, Engineer)
True
>>> isinstance(watney, Pilot)
True
>>> isinstance(watney, Astronaut)
True
9.6.5. Multiple Inheritance¶
>>> class Engineer:
... pass
>>>
>>> class Pilot:
... pass
>>>
>>> class Astronaut(Engineer, Pilot):
... pass
>>>
>>>
>>> watney = Astronaut()
>>> type(watney)
<class 'Astronaut'>
>>> isinstance(watney, Engineer)
True
>>> isinstance(watney, Pilot)
True
>>> isinstance(watney, Astronaut)
True
9.6.6. Overload¶
>>> class A:
... def show(self):
... return 'a'
>>>
>>> class B(A):
... pass
>>>
>>>
>>> obj = B()
>>> obj.show()
'a'
>>>
>>>
>>> class A:
... def show(self):
... return 'a'
>>>
>>> class B(A):
... def show(self):
... return 'b'
>>>
>>>
>>> obj = B()
>>> obj.show()
'b'
>>> class Person:
... lastname = 'Watney'
...
... def hello(self):
... print(f'Hello {self.firstname} {self.lastname}')
>>>
>>>
>>> class Astronaut(Person):
... firstname = 'Mark'
>>>
>>>
>>> a = Astronaut()
>>> a.hello()
Hello Mark Watney
9.6.7. Super Function¶
>>> class A:
... def show(self):
... return 'a'
>>>
>>> class B(A):
... def show(self):
... old_value = super().show()
... return old_value + 'b'
>>>
>>>
>>> obj = B()
>>> obj.show()
'ab'
>>> class Engineer:
... def __init__(self):
... self.education = 'Engineer'
... self.profession = 'Engineer'
>>>
>>> class Astronaut(Engineer):
... def __init__(self):
... super().__init__()
... self.profession = 'Astronaut'
>>>
>>>
>>> mark = Astronaut()
>>>
>>> print(mark.__dict__) # doctest: +NORMALIZE_WHITESPACE
{'education': 'Engineer',
'profession': 'Astronaut'}
>>> class Engineer:
... def __init__(self):
... self.education = 'Engineer'
... self.profession = 'Engineer'
>>>
>>> class Astronaut(Engineer):
... def __init__(self):
... self.profession = 'Astronaut'
... super().__init__()
>>>
>>>
>>> mark = Astronaut()
>>>
>>> print(mark.__dict__) # doctest: +NORMALIZE_WHITESPACE
{'profession': 'Engineer',
'education': 'Engineer'}
>>> class Engineer:
... def __init__(self, firstname, lastname):
... self.firstname = firstname
... self.lastname = lastname
... self.education = 'Engineer'
... self.profession = 'Engineer'
>>>
>>> class Astronaut(Engineer):
... def __init__(self, firstname, lastname):
... super().__init__(firstname, lastname)
... self.profession = 'Astronaut'
>>>
>>>
>>> mark = Astronaut('Mark', 'Watney')
>>>
>>> print(mark.__dict__) # doctest: +NORMALIZE_WHITESPACE
{'firstname': 'Mark',
'lastname': 'Watney',
'education': 'Engineer',
'profession': 'Astronaut'}
9.6.8. Inheritance vs Composition¶
>>> class Car:
... def engine_start(self):
... print('Starting engine...')
>>>
>>>
>>> class Truck:
... def engine_start(self):
... print('Starting engine...')
Simple Inheritance:
>>> class Vehicle:
... def engine_start(self):
... print('Starting engine...')
>>>
>>>
>>> class Car(Vehicle):
... pass
>>>
>>> class Truck(Vehicle):
... pass
Inheritance Problem:
>>> class Vehicle:
... def engine_start(self):
... print('Starting engine...')
>>>
>>>
>>> class Car(Vehicle):
... def windows_open(self):
... print('Opening windows...')
>>>
>>>
>>> class Truck(Vehicle):
... def windows_open(self):
... print('Opening windows...')
>>>
>>>
>>> class Motorcycle(Vehicle):
... pass
Not Implemented Error:
>>> class Vehicle:
... def engine_start(self):
... print('Starting engine...')
...
... def windows_open():
... print('Opening windows...')
>>>
>>>
>>> class Car(Vehicle):
... pass
>>>
>>> class Truck(Vehicle):
... pass
>>>
>>> class Motorcycle(Vehicle):
... def windows_open(self):
... raise NotImplementedError('Has no windows')
Composition:
>>> class Vehicle:
... def engine_start(self):
... print('Starting engine...')
...
... def engine_stop():
... print('Stopping engine...')
>>>
>>>
>>> class HasWindows:
... def windows_open(self):
... print('Opening windows...')
>>>
>>>
>>> class Car(Vehicle, HasWindows):
... pass
>>>
>>> class Truck(Vehicle, HasWindows):
... pass
>>>
>>> class Motorcycle(Vehicle):
... pass
9.6.9. Use Cases¶
>>> class Iris:
... def __init__(self, sepal_length, sepal_width,
... petal_length, petal_width, species):
...
... self.sepal_length = sepal_length
... self.sepal_width = sepal_width
... self.petal_length = petal_length
... self.petal_width = petal_width
... self.species = species
>>>
>>>
>>> class Setosa(Iris):
... pass
>>>
>>> class Versicolor(Iris):
... pass
>>>
>>> class Virginica(Iris):
... pass
>>>
>>>
>>> setosa = Setosa(
... sepal_length=5.1,
... sepal_width=3.5,
... petal_length=1.4,
... petal_width=0.2,
... species='setosa')
9.6.10. Assignments¶
"""
* Assignment: OOP Inheritance Simple
* Complexity: easy
* Lines of code: 4 lines
* Time: 3 min
English:
1. Use data from "Given" section (see below)
2. Create class `Woman` which inherits from `Venus`
3. Create class `Man` which inherits from `Mars`
Polish:
1. Użyj danych z sekcji "Given" (patrz poniżej)
2. Stwórz klasę `Woman`, która dziedziczy po `Venus`
3. Stwórz klasę `Man`, która dziedziczy po `Mars`
Tests:
>>> from inspect import isclass
>>> assert isclass(Venus)
>>> assert isclass(Woman)
>>> assert isclass(Mars)
>>> assert isclass(Man)
>>> assert issubclass(Woman, Venus)
>>> assert issubclass(Man, Mars)
"""
# Given
class Venus:
pass
class Mars:
pass
"""
* Assignment: OOP Inheritance Multiple
* Complexity: easy
* Lines of code: 2 lines
* Time: 2 min
English:
1. Use data from "Given" section (see below)
2. Create class `Astronaut` which inherits from all of those classes
3. Compare result with "Tests" section (see below)
Polish:
1. Use data from "Given" section (see below)
2. Stwórz klasę `Astronaut`, która dziedziczy po tych wszystkich klasach
3. Porównaj wyniki z sekcją "Tests" (patrz poniżej)
Tests:
>>> from inspect import isclass
>>> assert isclass(Scientist)
>>> assert isclass(Engineer)
>>> assert isclass(Pilot)
>>> assert isclass(MedicalDoctor)
>>> assert isclass(Astronaut)
>>> assert issubclass(Astronaut, Scientist)
>>> assert issubclass(Astronaut, Engineer)
>>> assert issubclass(Astronaut, Pilot)
>>> assert issubclass(Astronaut, MedicalDoctor)
"""
# Given
class Scientist:
pass
class Engineer:
pass
class Pilot:
pass
class MedicalDoctor:
pass
"""
* Assignment: OOP Inheritance Super
* Complexity: easy
* Lines of code: 6 lines
* Time: 5 min
English:
1. Use data from "Given" section (see below)
2. Create class `Astronaut` which inherits from `Person`
3. Class `Astronaut` takes two arguments `name` and `mission`
4. Set attribute `mission` in `Astronaut` inicializer method
5. Call initializer method of `Person` passing `name` as an argument
6. Define method `show()` returning name and after coma - a mission name
6. Compare result with "Tests" section (see below)
Polish:
1. Użyj danych z sekcji "Given" (patrz poniżej)
2. Stwórz klasę `Astronaut` dziedziczącą po `Person`
3. Klasa `Astronaut` przyjmuje dwa argumenty `name` i `mission`
4. Ustaw atrybut `mission` w metodzie inicjalizacyjnej w `Astronaut`
5. Wywołaj metodę inicjalizacyjną z `Person` podając `name` jako argument
6. Zdefiniuj metodę `show()` zwracającą imię i po przecinku - nazwę misji
7. Porównaj wyniki z sekcją "Tests" (patrz poniżej)
Tests:
>>> watney = Astronaut('Watney', 'Ares 3')
>>> watney.show()
'Watney, Ares 3'
>>> lewis = Astronaut('Lewis', 'Ares 3')
>>> lewis.show()
'Lewis, Ares 3'
"""
# Given
class Person:
def __init__(self, name):
self.name = name