6.4. Inheritance Super

  • Raymond Hettinger - Super considered super! - PyCon 2015 [1]

>>> class User:
...     def login(self):
...         ...
>>>
>>> class Admin(User):
...     def login(self):
...         super().login()

Note that in Python 3, you don't need to pass any arguments to super(), it can figure out which class it is being called from and work automatically. In Python 2 you had to specify the current class, but that's not needed any more.

Note

Source [3] [2]

6.4.1. Problem

>>> class User:
...     def login(self):
...         print('User login')
>>>
>>> class Admin(User):
...     def login(self):
...         print('Admin login')
>>>
>>>
>>> mark = Admin()
>>> mark.login()
Admin login

6.4.2. Solution

>>> class User:
...     def login(self):
...         print('User login')
>>>
>>> class Admin(User):
...     def login(self):
...         super().login()
...         print('Admin login')
>>>
>>>
>>> mark = Admin()
>>> mark.login()
User login
Admin login

6.4.3. Super Order

  • Order is important

Super first:

>>> class User:
...     def login(self):
...         print('User login')
>>>
>>> class Admin(User):
...     def login(self):
...         super().login()
...         print('Admin login')
>>>
>>>
>>> mark = Admin()
>>> mark.login()
User login
Admin login

Super last:

>>> class User:
...     def login(self):
...         print('User login')
>>>
>>> class Admin(User):
...     def login(self):
...         print('Admin login')
...         super().login()
>>>
>>>
>>> mark = Admin()
>>> mark.login()
Admin login
User login

6.4.4. Super Init

  • Call to __init__ of super class is missed

>>> class User:
...     def __init__(self, firstname, lastname):
...         self.firstname = 'Mark'
...         self.lastname = 'Watney'
...         self.role = 'user'
>>>
>>> class Admin(User):
...     def __init__(self, firstname, lastname):
...         super().__init__(firstname, lastname)
...         self.role = 'admin'
>>> mark = User('Mark', 'Watney')
>>> vars(mark)
{'firstname': 'Mark', 'lastname': 'Watney', 'role': 'user'}
>>> mark = Admin('Mark', 'Watney')
>>> vars(mark)
{'firstname': 'Mark', 'lastname': 'Watney', 'role': 'admin'}

6.4.5. Init and Multiple Inheritance

Multiple inheritance in Python needs to be cooperative. That is, the two parent classes need to be aware of the possibility that each other exist (though they don't need to know any of each other's details). Then whichever parent is named first can call the other parent's __init__ method. That's how super works, it always calls the next class in the MRO (the method resolution order) of the instance being operated on.

>>> from pprint import pprint
>>> class NameMixin:
...     def __init__(self, firstname, lastname, *args, **kwargs):
...         self.firstname = firstname
...         self.lastname = lastname
...         super().__init__(*args, **kwargs)
>>>
>>> class GroupsMixin:
...     def __init__(self, groups, *args, **kwargs):
...         self.groups = groups
...         super().__init__(*args, **kwargs)
>>>
>>>
>>> class User(NameMixin, GroupsMixin):
...     def __init__(self, firstname, lastname, groups):
...         super().__init__(firstname, lastname, groups)
>>> mark = User('Mark', 'Watney', groups=['users', 'staff', 'admins'])
>>>
>>> pprint(vars(mark), sort_dicts=False)
{'firstname': 'Mark',
 'lastname': 'Watney',
 'groups': ['users', 'staff', 'admins']}

6.4.6. References