Використання функції super() у класах Python

Ключові висновки

  • Функція Python super() дозволяє викликати методи суперкласу з підкласу, полегшуючи реалізацію успадкування та перевизначення методів.
  • Функція super() тісно пов’язана з порядком вирішення методів (MRO) у Python, який визначає порядок, у якому класи-предки шукають методи або атрибути.
  • Використання super() у конструкторах класів є звичайною практикою для ініціалізації загальних атрибутів у батьківському класі та більш специфічних у дочірньому класі. Невикористання super() може призвести до непередбачуваних наслідків, таких як відсутність ініціалізації атрибутів.

Однією з основних особливостей Python є його парадигма ООП, яку можна використовувати для моделювання об’єктів реального світу та їхніх зв’язків.

Працюючи з класами Python, ви часто використовуєте успадкування та замінюєте атрибути або методи суперкласу. Python надає функцію super(), яка дозволяє викликати методи суперкласу з підкласу.

Що таке super() і навіщо він потрібен?

Використовуючи успадкування, ви можете створити новий клас Python, який успадковує функції існуючого класу. Ви також можете перевизначати методи суперкласу в підкласі, надаючи альтернативні реалізації. Однак ви можете використовувати нову функцію на додаток до старої, а не замість неї. У цьому випадку корисно використовувати super().

Ви можете використовувати функцію super() для доступу до атрибутів суперкласу та виклику методів суперкласу. Super необхідний для об’єктно-орієнтованого програмування, оскільки він полегшує реалізацію успадкування та перевизначення методів.

Як працює super()?

Внутрішньо super() тісно пов’язаний із порядком вирішення методу (MRO) у Python, який визначає алгоритм лінеаризації C3.

Ось як працює super():

  • Визначення поточного класу та екземпляра: коли ви викликаєте super() всередині методу підкласу, Python автоматично визначає поточний клас (клас, що містить метод, який викликав super()) і екземпляр цього класу (тобто self) .
  • Визначте суперклас: супер() приймає два аргументи — поточний клас і екземпляр, — які вам не потрібно передавати явно. Він використовує цю інформацію для визначення суперкласу для делегування виклику методу. Це робиться шляхом вивчення ієрархії класів і MRO.
  • Викликати метод у суперкласі: після визначення суперкласу super() дозволяє викликати його методи так, ніби ви викликаєте їх безпосередньо з підкласу. Це дає змогу розширювати або замінювати методи, продовжуючи використовувати оригінальну реалізацію з суперкласу.
  • Використання super() у конструкторі класів

    Використання super() у конструкторі класу є звичайною практикою, оскільки часто потрібно ініціалізувати загальні атрибути в батьківському класі та більш специфічні в дочірньому.

    Щоб продемонструвати це, визначте клас Python, Father, який успадковує клас Son:

     class Father:
        def __init__(self, first_name, last_name):
            self.first_name = first_name
            self.last_name = last_name

    class Son(Father):
        def __init__(self, first_name, last_name, age, hobby):
            
            super().__init__(first_name, last_name)

            self.age = age
            self.hobby = hobby

        def get_info(self):
            return f"Son's Name: {self.first_name} {self.last_name}, \
    Son's Age: {self.age}, Son's Hobby: {self.hobby}"


    son = Son("Pius", "Effiong", 25, "Playing Guitar")


    print(son.get_info())

    Всередині конструктора Son виклик super().init() викликає конструктор класу Father, передаючи йому first_name і last_name як параметри. Це гарантує, що клас Father все ще може правильно встановлювати атрибути імені навіть для об’єкта Son.

    Якщо ви не викликаєте super() у конструкторі класу, конструктор його батьківського класу не запускатиметься. Це може призвести до небажаних наслідків, таких як відсутність ініціалізації атрибутів або неповне налаштування стану батьківського класу:

     ...
    class Son(Father):
        def __init__(self, first_name, last_name, age, hobby):
            self.age = age
            self.hobby = hobby
    ...

    Якщо ви зараз спробуєте викликати метод get_info, він викличе помилку AttributeError, оскільки атрибути self.first_name і self.last_name не було ініціалізовано.

    Використання super() у методах класу

    Ви можете використовувати super() в інших методах, окрім конструкторів, таким же чином. Це дозволяє розширити або змінити поведінку методу суперкласу.

     class Father:
        def speak(self):
            return "Hello from Father"

    class Son(Father):
        def speak(self):
            
            parent_greeting = super().speak()
            return f"Hello from Son\n{parent_greeting}"


    son = Son()


    son_greeting = son.speak()

    print(son_greeting)

    Клас Синів успадковує від Батька і має свій метод розмови. Метод speak класу Son використовує super().speak() для виклику методу speak класу Father. Це дозволяє включити повідомлення від батьківського класу, розширюючи його повідомленням, специфічним для дочірнього класу.

    Невикористання super() у методі, який замінює інший, означає, що функціональні можливості, присутні в методі батьківського класу, не діятимуть. Це призводить до повної заміни поведінки методу, що може призвести до поведінки, якої ви не бажали.

    Розуміння порядку вирішення методу

    Порядок визначення методу (MRO) — це порядок, у якому Python шукає класи предків, коли ви отримуєте доступ до методу або атрибута. MRO допомагає Python визначити, який метод викликати, якщо існує кілька ієрархій успадкування.

     class Nigeria():
        def culture(self):
            print("Nigeria's culture")

    class Africa():
       def culture(self):
           print("Africa's culture")

    Ось що відбувається, коли ви створюєте екземпляр класу Lagos і викликаєте метод культури:

  • Python починає з пошуку методу культури в самому класі Lagos. Якщо він знаходить його, він викликає метод. Якщо ні, він переходить до другого кроку.
  • Якщо він не знаходить метод культури в класі Lagos, Python переглядає базові класи в тому порядку, в якому вони з’являються у визначенні класу. У цьому випадку Лагос отримує спадок спочатку від Африки, а потім від Нігерії. Отже, Python спочатку шукатиме метод культури в Африці.
  • Якщо він не знайде метод культури в класі Africa, Python шукатиме в класі Nigeria. Така поведінка продовжується, доки він не досягне кінця ієрархії та викине помилку, якщо не зможе знайти метод у жодному з суперкласів.
  • Результат показує порядок вирішення методу Lagos, починаючи зліва направо.

    Поширені підводні камені та найкращі практики

    Під час роботи з super() є деякі типові підводні камені, яких слід уникати.

  • Пам’ятайте про порядок вирішення методів, особливо в сценаріях множинного успадкування. Якщо вам потрібно використовувати складне множинне успадкування, ви повинні бути знайомі з C3 Алгоритм лінеаризації який Python використовує для визначення MRO.
  • Уникайте циклічних залежностей у вашій ієрархії класів, які можуть призвести до непередбачуваної поведінки.
  • Чітко задокументуйте свій код, особливо коли використовуєте super() у складних ієрархіях класів, щоб зробити його більш зрозумілим для інших розробників.
  • Використовуйте super() правильно

    Функція Python super() є потужною функцією, коли ви працюєте з успадкуванням і перевизначенням методів. Розуміння того, як працює super() і дотримання найкращих практик, дозволить вам створювати більш зручний і ефективний код у ваших проектах Python.