Функція super() – це вбудована функція Python, котра повертає тимчасовий об’єкт батьківського класу, що дає змогу отримати доступ до атрибутів та методів батьківського класу, всередині його підкласу.
Під час виклику super() всередині методу підкласу, Python автоматично визначає поточний клас та екземпляр цього класу (тобто self). Ця інформація використовується для визначення суперкласу, якому слід делегувати виклик методу (шляхом вивчення ієрархії класів та MRO – Method Resolution Order). Визначивши суперклас, super() дозволяє звертатись до його атрибутів та викликати його методи, всередині підкласу. Це дає змогу розширяти або перевизначати методи в підкласі, використовуючи при цьому оригінальну реалізацію з суперкласу.
Використання super() у конструкторі класу
Приклад використання super() у конструкторі класу, для ініціалізації атрибутів батьківського класу:
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
class Employee(Person):
def __init__(self, name, age, job):
super().__init__(name, age)
self.job = job
def __str__(self):
return f'{self.name}, {self.age}, {self.job}'
manager = Employee('Santiago Cross', 32, 'manager')
print(manager)
# Santiago Cross, 32, managerВсередині конструктора класу Employee, виклик super().__init__() (рядок 11), викликає конструктор класу Person, передаючи йому name та age як параметри. Це гарантує, що атрибути батьківського класу name та age будуть ініційовані, під час створення об’єкта класу спадкоємця.
Використання super() у методах класу
В той самий спосіб можна використовувати super() в інших методах класу, що може бути корисним для розширення або перевизначення поведінки методу суперкласу:
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def __str__(self):
return f'{self.name}, {self.age}'
class Employee(Person):
def __init__(self, name, age, job):
super().__init__(name, age)
self.job = job
def __str__(self):
person = super().__str__()
return f'{person}, {self.job}'
manager = Employee('Santiago Cross', 32, 'manager')
print(manager)
# Santiago Cross, 32, managerМетод __str__() класу спадкоємця Employee, використовує super().__str__() (рядок 18), для виклику однойменного методу з батьківського класу Person. Це дає змогу отримати інформацію з батьківського класу, розширивши її специфічною інформацією дочірнього класу (тобто доповнити поведінку, замість того щоб переписувати її заново).
Method Resolution Order (MRO)
Method Resolution Order (MRO) – це порядок, в котрому Python шукає батьківські класи, під час звернення до методу або атрибуту. MRO допомагає Python визначити, який саме метод викликати в ієрархії успадкування.
Розглянемо що відбувається після створення екземпляра класу С, та виклику методу message (рядок 16) з прикладу нижче:
class A:
def message(self):
print('Message A')
class B:
def message(self):
print('Message B')
class C(B, A):
pass
c = C()
c.message() # Message B
print(C.__mro__)
# (<class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <class 'object'>)- Python починає з пошуку методу message у самому класі C. Якщо метод знайдено, відбувається виклик реалізації методу з класу C.
- Якщо метод message не знайдено в класі C, Python переглядає батьківські класи в порядку, в котрому вони прописані під час визначення класу. В цьому випадку, клас С спочатку успадковує клас B, а потім клас A. Отже, пошук методу message, попередньо відбувається саме в класі B. Якщо метод знайдено, відбувається його виклик.
- Якщо в класі B метод message не знайдено, пошук продовжиться в класі A. Така поведінка продовжується до досягнення кінця ієрархії. Якщо метод не знайдено в жодному з батьківських класів, буде отримано помилку.
Доступ до MRO можна отримати за допомогою атрибута класу __mro__ (рядки 18-19 в прикладі вище), завдяки чому побачити порядок, в якому Python буде шукати методи.