9.6. Inheritance

9.6.1. Rationale

  • Child inherits all fields and methods from parent

  • Used to avoid code duplication

parent
superclass
base class

Class from other classes inherits

child
subclass

Class which inherits from parent

overload

When child has method or attribute with the same name as parent. In such case child attribute will be used (will overload parent).

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. Example

class Car:
    def engine_start():
        print('Starting engine...')

    def engine_stop():
        print('Stopping engine...')


class Truck:
    def engine_start():
        print('Starting engine...')

    def engine_stop():
        print('Stopping engine...')
class Vehicle:
    def engine_start():
        print('Starting engine...')

    def engine_stop():
        print('Stopping engine...')


class Car(Vehicle):
    pass

class Truck(Vehicle):
    pass

9.6.4. 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'

9.6.5. Simple Inheritance

class Vehicle:
    pass


class Car(Vehicle):
    pass

class Truck(Vehicle):
    pass
class Engineer:
    def __init__(self, first_name, last_name):
        self.first_name = first_name
        self.last_name = last_name

class Astronaut(Engineer):
    pass

class Cosmonaut(Engineer):
    pass


mark = Astronaut('Mark', 'Watney')
ivan = Cosmonaut('Ivan', 'Ivanovic')
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.6. Multilevel Inheritance

Listing 9.40. Multilevel Inheritance
class Scientist:
    pass

class Engineer(Scientist):
    pass

class Astronaut(Engineer):
    pass


watney = Astronaut()

isinstance(watney, Scientist)   # True
isinstance(watney, Engineer)    # True
isinstance(watney, Astronaut)   # True

type(watney)                    # <class '__main__.Astronaut'>
class Vehicle:
    pass


class Car(Vehicle):
    def windows_open():
        print('Opening windows...')


class Truck(Vehicle):
    def windows_open():
        print('Opening windows...')


class Motorcycle(Vehicle):
    pass
class Vehicle:
    def windows_open():
        print('Opening windows...')


class Car(Vehicle):
    pass

class Truck(Vehicle):
    pass

class Motorcycle(Vehicle):
    def windows_open():
        raise NotImplementedError('Has no windows')

9.6.7. Multiple Inheritance

Listing 9.41. Multiple Inheritance
class Scientist:
    pass

class Engineer:
    pass

class Astronaut(Scientist, Engineer):
    pass


watney = Astronaut()

isinstance(watney, Scientist)   # True
isinstance(watney, Engineer)    # True
isinstance(watney, Astronaut)   # True

type(watney)                    # <class '__main__.Astronaut'>
class Vehicle:
    pass

class HasWindows:
    pass


class Car(Vehicle, HasWindows):
    pass

class Truck(Vehicle, HasWindows):
    pass

class Motorcycle(Vehicle):
    pass

9.6.8. Calling Parent Methods

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__)
# {'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__)
# {'education': 'Engineer',
#  'profession': 'Engineer'}
class Engineer:
    def __init__(self, first_name, last_name):
        self.first_name = first_name
        self.last_name = last_name
        self.education = 'Engineer'
        self.profession = 'Engineer'

class Astronaut(Engineer):
    def __init__(self, first_name, last_name):
        super().__init__(first_name, last_name)
        self.profession = 'Astronaut'


mark = Astronaut('Mark', 'Watney')

print(mark.__dict__)
# {'first_name': 'Mark',
#  'last_name': 'Watney',
#  'education': 'Engineer',
#  'profession': 'Astronaut'}

9.6.9. Assignments

9.6.9.1. OOP Inheritance Simple

English
  1. Create class Mars

  2. Create class Venus

  3. Create class Woman which inherits from Venus

  4. Create class Man which inherits from Mars

Polish
  1. Stwórz klasę Mars

  2. Stwórz klasę Venus

  3. Stwórz klasę Woman, która dziedziczy po Venus

  4. Stwórz klasę Man, która dziedziczy po Mars

9.6.9.2. OOP Inheritance Multiple

English
  1. Create classes Engineer, Scientist, Pilot, MedicalDoctor

  2. Create class Astronaut which inherits from all of those classes

Polish
  1. Stwórz klasy Engineer, Scientist, Pilot, MedicalDoctor

  2. Stwórz klasę Astronaut, która dziedziczy po tych wszystkich klasach

9.6.9.3. OOP Inheritance Init

English
  1. Use data from "Input" section (see below)

  2. Create class Crew

  3. In __init__() set mission to Ares 3

  4. Create class Astronaut which inherits from Crew

  5. Using positional arguments at the initialization set astronaut first name and last name

  6. All astronauts must have assigned mission (inherited from Crew)

  7. Return first name, last name and mission name from __str__()

  8. Compare result with "Output" section (see below)

Polish
  1. Użyj danych z sekcji "Input" (patrz poniżej)

  2. Stwórz klasę Crew

  3. W __init__() ustaw mission na Ares 3

  4. Stwórz klasę Astronaut dziedziczącą po Crew

  5. Używając parametrów pozycyjnych podanych przy inicjalizacji ustaw imię i nazwisko astronauty

  6. Każdy astronauta musi mieć przydzieloną misję (odziedziczoną z Crew)

  7. Zwróć imię, nazwisko i nazwę misji from __str__()

  8. Porównaj wyniki z sekcją "Output" (patrz poniżej)

Input
mark = Astronaut('Mark Watney')
melissa = Astronaut('Melissa Lewis')
alex = Astronaut('Alex Vogel')

result = f"""
Astronaut crew:
- {mark}
- {melissa}
- {alex}
"""

print(result)
Output
Astronaut crew:
- Mark Watney (Ares 3)
- Melissa Lewis (Ares 3)
- Alex Vogel (Ares 3)