Inheritance

Extending Existing Classes

  • Person is not enough

  • Want Employee

  • is-a Person, but with additional features

  • Implementation inheritance

    class Person:
        def __init__(self, firstname, lastname):
            self.firstname = firstname
            self.lastname = lastname
    
        def fullname(self):
            return f'{self.firstname} {self.lastname}'
    
    class Employee(Person):  # <--- is-a Person
        pass
    

Creating an instance of Employee

  • Employee: no __init__()

  • Person: found

  • Person.__init__() called

    emp = Employee('Joerg', 'Faschingbauer')
    emp.fullname()
    
    'Joerg Faschingbauer'
    

Additional Feature: Salary

  • Employee needs its own constructor (added salary)

  • Calls base classe constructor ⟶ super()

    class Employee(Person):
        def __init__(self, firstname, lastname, salary):
            super().__init__(firstname, lastname)   # <--- Person.__init__()
            self.salary = salary
    
        def title(self):
            return f'{self.fullname()} ({self.salary})'
    
  • Now calling Employee.__init__()

  • … which in turn calls Person.__init__()

    emp = Employee('Joerg', 'Faschingbauer', 6000)
    emp.title()
    
    'Joerg Faschingbauer (6000)'
    

Want Manager

Another class, Manager, in the tree …

class Manager(Employee):
    def __init__(self, firstname, lastname, salary, employees):
        super().__init__(firstname, lastname, salary) # <--- Employee.__init__()
        self.employees = employees

    def add_employee(self, employee):
        self.employees.append(employee)

    def title(self):
        title = super().title()
        return title + f' (manages {len(self.employees)} employees)'

Composing a number of objects into a Manager instance …

joerg = Employee('Joerg', 'Faschingbauer', 6000)
mgr = Manager('Isolde', 'Haubentaucher', 10000, [joerg])
caro = Employee('Caro', 'Faschingbauer', 5000)
mgr.add_employee(caro)

mgr.title()
'Isolde Haubentaucher (10000) (manages 2 employees)'

Introspecting Inheritance: isinstance(), issubclass()

  • isinstance(object, cls): is object an instance of cls (or of a base class thereof)?

  • issubclass(cls, parentcls): is cls a subclass of parentcls?

    • Funnily a class is considered a subclass of itself

isinstance()

Obviously an Employee instance is an Employee instance:

joerg = Employee('Joerg', 'Faschingbauer', 6000)
isinstance(joerg, Employee)
True

He is also a Person:

isinstance(joerg, Person)
True

But not a Manager:

isinstance(joerg, Manager)
False

issubclass()

Manager is-a Person

issubclass(Manager, Person)
True

… but not the other way around:

issubclass(Person, Manager)
False

Funnily, Person is-a Person:

issubclass(Person, Person)
True

Add __str__(), Creatively, After The Fact

Unrelated, but fun: add class methods dynamically …

Person.__str__ = Person.fullname
Employee.__str__ = Employee.title
Manager.__str__ = Manager.title

joerg = Employee('Joerg', 'Faschingbauer', 6000)
mgr = Manager('Isolde', 'Haubentaucher', 10000, [joerg])
caro = Employee('Caro', 'Faschingbauer', 5000)
mgr.add_employee(caro)

print('joerg:', joerg)
print('mgr:', mgr)
joerg: Joerg Faschingbauer (6000)
mgr: Isolde Haubentaucher (10000) (manages 2 employees)