Что делает super в python
Функция super() в Python: вызов методов родительского класса
19 марта 2023
Оценки статьи
Еще никто не оценил статью
Функция super() в Python используется для вызова методов родительского класса. В этой статье мы рассмотрим, что такое super() , как он работает, и как его можно использовать.
Что такое super() в Python?
super() — это функция, которая позволяет вызывать методы родительского класса в дочернем классе. Она используется, когда нужно вызвать методы родительского класса в дочернем классе, чтобы избежать дублирования кода и улучшить его читаемость.
Функция super() можно использовать для вызова методов как в методах, так и в конструкторах дочернего класса.
Как работает функция super() в Python?
Когда мы создаем дочерний класс, он наследует все атрибуты и методы родительского класса. Для того, чтобы вызвать метод родительского класса, мы можем использовать функцию super() .
При вызове super() Python ищет родительский класс в иерархии наследования, начиная с текущего класса и переходя к родительским классам в порядке, заданном в списке наследования. После нахождения родительского класса, super() вызывает его методы и передает все аргументы, которые были переданы методу дочернего класса.
Пример использования super() в Python
Рассмотрим пример, который показывает, как использовать super() для вызова метода родительского класса.
class Animal: def __init__(self, name): self.name = name def make_sound(self): print("The animal makes a sound") class Dog(Animal): def __init__(self, name): super().__init__(name) def make_sound(self): super().make_sound() print("The dog barks") my_dog = Dog("Buddy") my_dog.make_sound()
В этом примере у нас есть два класса: Animal и Dog . Класс Dog наследует от Animal .
Мы переопределяем метод make_sound() в классе Dog , но вместо того, чтобы полностью переписывать метод, мы вызываем метод make_sound родительского класса с помощью super() , а затем добавляем к нему свой код.
Результат выполнения этого кода будет:
>>> The animal makes a sound >>> The dog barks
В этом примере мы вызываем метод make_sound() родительского класса с помощью super() , а затем добавляем к нему свой код, чтобы сделать ту же самую вещь, но с дополнительным функционалом.
Функция super() в Python
Функция super() в Python позволяет нам явно ссылаться на родительский класс. Это полезно в случае наследования, когда мы хотим вызывать функции суперкласса. В Python Inheritance подклассы наследуются от суперкласса.
Функция super() позволяет нам неявно ссылаться на суперкласс. Итак, super делает нашу задачу проще и удобнее. Ссылаясь на суперкласс из подкласса, нам не нужно явно писать имя суперкласса.
Пример функции
Сначала просто посмотрите на следующий код, который мы использовали в нашем руководстве по наследованию. В этом примере кода суперклассом был Person, а подклассом – Student. Итак, код показан ниже.
class Person: # initializing the variables name = "" age = 0 # defining constructor def __init__(self, person_name, person_age): self.name = person_name self.age = person_age # defining class methods def show_name(self): print(self.name) def show_age(self): print(self.age) # definition of subclass starts here class Student(Person): studentId = "" def __init__(self, student_name, student_age, student_id): Person.__init__(self, student_name, student_age) self.studentId = student_id def get_id(self): return self.studentId # returns the value of student id # end of subclass definition # Create an object of the superclass person1 = Person("Richard", 23) # call member methods of the objects person1.show_age() # Create an object of the subclass student1 = Student("Max", 22, "102") print(student1.get_id()) student1.show_name()
В приведенном выше примере мы вызвали функцию родительского класса, как:
Person.__init__(self, student_name, student_age)
Мы можем заменить это вызовом функции, как показано ниже:
super().__init__(student_name, student_age)
Результат останется таким же в обоих случаях, как показано на изображении ниже:

Функция для Python 3
Обратите внимание, что приведенный выше синтаксис предназначен для функции super() в python 3. Если вы используете версию Python 2.x, она немного отличается, и вам придется внести следующие изменения:
class Person(object): . super(Student, self).__init__(student_name, student_age)
Первое изменение – сделать объект базовым классом для Person. В версиях Python 2.x необходимо использовать функцию super. В противном случае вы получите следующую ошибку:
Traceback (most recent call last): File "super_example.py", line 40, in student1 = Student("Max", 22, "102") File "super_example.py", line 25, in __init__ super(Student, self).__init__(student_name, student_age) TypeError: must be type, not classobj
Второе изменение синтаксиса самой функции. Как видите, функция в python 3 намного проще в использовании, и синтаксис также выглядит чистым.
Функция super() с многоуровневым наследованием
Как мы уже заявляли ранее, super() позволяет нам неявно ссылаться на суперкласс.
Но в случае многоуровневого наследования, к какому классу оно будет относиться? super() всегда будет ссылаться на непосредственный суперкласс.
Также функция может не только ссылаться на функцию __init __(), но также может вызывать все другие функции суперкласса. Итак, в следующем примере мы увидим это:
class A: def __init__(self): print('Initializing: class A') def sub_method(self, b): print('Printing from class A:', b) class B(A): def __init__(self): print('Initializing: class B') super().__init__() def sub_method(self, b): print('Printing from class B:', b) super().sub_method(b + 1) class C(B): def __init__(self): print('Initializing: class C') super().__init__() def sub_method(self, b): print('Printing from class C:', b) super().sub_method(b + 1) if __name__ == '__main__': c = C() c.sub_method(1)
Давайте посмотрим на результат вышеприведенного примера в python 3 с многоуровневым наследованием.
Initializing: class C Initializing: class B Initializing: class A Printing from class C: 1 Printing from class B: 2 Printing from class A: 3
Итак, из выходных данных мы ясно видим, что сначала была вызвана функция __init __() класса C, затем класса B, а затем класса A. Аналогичная вещь произошла при вызове функции sub_method().
Зачем нужна функция super()?
Если у вас есть предыдущий опыт работы с языком Java, вы должны знать, что базовый класс также вызывается там супер объектом. Итак, эта концепция действительно полезна для кодеров. Однако Python также позволяет программисту использовать имя суперкласса для ссылки на него. И, если ваша программа содержит многоуровневое наследование, эта функция будет вам полезна.
Введение в множественное наследование и super()
Введение в множественное наследование и super() для Python-разработчиков. Также в этой статье мы рассмотрим, как справляться с проблемой алмаза.
Краткий обзор наследования
По мере расширения ваших проектов и пакетов Python вы неизбежно захотите использовать классы и т.о. применять один из фундаментальных принципов программирования – принцип DRY (Don’t repeat yourself – не повторяйся!). Наследование классов — это фантастический способ создать класс на основе другого класса, следуя принципу DRY.
В этой статье мы рассмотрим более продвинутые концепции наследования, не останавливаясь на базовых вещах. По основам лишь кратко пройдемся в этом вступлении.
Так что же такое наследование классов? Подобно тому, как это происходит в генетике, дочерний класс может «наследовать» атрибуты и методы от родителя. Давайте сразу перейдем к коду для демонстрации и лучшего понимания.
В приведенном ниже блоке кода мы продемонстрируем наследование. У нас есть дочерний класс Child , наследуемый от родительского класса Parent .
class Parent: def __init__(self): self.parent_attribute = 'I am a parent' def parent_method(self): print('Back in my day. ') # Create a child class that inherits from Parent class Child(Parent): def __init__(self): Parent.__init__(self) self.child_attribute = 'I am a child' # Create instance of child child = Child() # Show attributes and methods of child class print(child.child_attribute) print(child.parent_attribute) child.parent_method()
Давайте его запустим и получим следующий результат:
I am a child I am a parent Back in my day.
Мы видим, что класс Child «унаследовал» атрибуты и методы от класса Parent . Без какой-либо работы с нашей стороны метод Parent.parent_method является частью класса Child . Чтобы воспользоваться методом Parent.__init__() , нам нужно было явно вызвать метод и передать self . Это потому, что, когда мы добавили метод __init__ в Child , мы перезаписали унаследованный __init__ .
После этого краткого и очень неполного обзора давайте перейдем к сути статьи.
Введение в super()
В простейшем случае функцию super() можно использовать для замены явного вызова Parent.__init__(self) . Наш вводный пример из первого раздела можно переписать с помощью super() , как это показано ниже.
Обратите внимание, что приведенный ниже блок кода написан на Python 3, более ранние версии используют немного другой синтаксис. Кроме того, вывод был опущен, поскольку он идентичен тому, что мы получили в первом примере.
Итак, при использовании super() наш код выглядел бы следующим образом:
class Parent: def __init__(self): self.parent_attribute = 'I am a parent' def parent_method(self): print('Back in my day. ') # Create a child class that inherits from Parent class Child(Parent): def __init__(self): super().__init__() self.child_attribute = 'I am a parent' # Create instance of child child = Child() # Show attributes and methods of child class print(child.child_attribute) print(child.parent_attribute) child.parent_method()
Честно говоря, super() в данном случае дает нам мало преимуществ, если вообще хоть что-то дает. В зависимости от имени нашего родительского класса мы можем сэкономить несколько нажатий клавиш, и нам не нужно передавать self вызову __init__ . Однако для других случаев super() может быть крайне полезен. Ниже приведены некоторые плюсы и минусы использования super() в случаях одиночного наследования.
Минусы
Можно сказать, что использование super() при одиночном наследовании делает код менее явным и интуитивно понятным. Создание менее явного кода нарушает дзен Python, в котором говорится: «Явное лучше, чем неявное».
Плюсы
С точки зрения поддерживаемости super() может быть полезен даже при одиночном наследовании. Если по какой-либо причине ваш дочерний класс меняет свой шаблон наследования (т.е. изменяется родительский класс или происходит переход к множественному наследованию), то нет необходимости искать и заменять все устаревшие ссылки на ParentClass.method_name() . Таким образом, использование super() позволит всем изменениям пройти через изменение в операторе класса.
Super() и множественное наследование
Прежде чем мы перейдем к множественному наследованию и super() , хотим сразу предупредить, что тема непростая. Однако потратьте немного своего времени, перечитайте статью несколько раз, и всё встанет на свои места!
Во-первых, что такое множественное наследование? Предыдущие примеры кода охватывали один дочерний класс Child , наследуемый от одного родительского класса Parent . При множественном наследовании существует более одного родительского класса. Дочерний класс может наследовать от 2, 3, 10 и т.д. родительских классов.
Вот где преимущества super() становятся более очевидными. В дополнение к экономии времени на нажатие клавиш для ссылки на разные имена родительских классов, есть нюансы в использовании super() со множественными шаблонами наследования. Короче говоря, если вы собираетесь использовать множественное наследование, то однозначно стоит использовать super() .
Множественное наследование без super()
Давайте рассмотрим пример множественного наследования без изменения каких-либо родительских методов и, в свою очередь, без super() .
Наш код будет выглядеть следующим образом:
class B: def b(self): print('b') class C: def c(self): print('c') class D(B, C): def d(self): print('d') d = D() d.b() d.c() d.d()
Вот такой результат мы получим:
b c d
Порядок разрешения методов
Полученный вывод не слишком удивителен, учитывая концепцию множественного наследования. D унаследовал методы b и c от своих родительских классов, и все в мире хорошо… пока что.
А что, если и B , и C имеют методы с одинаковыми именами? Именно здесь вступает в действие концепция, называемая «multiple-resolution order» (порядок разрешения методов в Python), или сокращенно MRO.
MRO дочернего класса определяет, где Python будет искать нужный метод и какой метод будет вызываться при возникновении конфликта.
Давайте рассмотрим следующий пример:
class B: def x(self): print('x: B') class C: def x(self): print('x: C') class D(B, C): pass d = D() d.x() print(D.mro()) # Output # x: B # [, , , ]
Когда мы вызываем унаследованный метод x , мы видим только выходные данные, унаследованные от класса B .
Мы можем увидеть MRO нашего класса D , вызвав метод класса mro() . Из вывода D.mro() мы узнаем следующее. По умолчанию наша программа попытается вызвать методы D , затем прибегнет к B , затем к C и, наконец, к классу object . Если метод не будет найден ни в одном из этих мест, то мы получим сообщение об ошибке, говорящее, что в D нет запрошенного нами метода.
Стоит отметить, что по умолчанию каждый класс наследуется от класса object , который и находится в конце каждого MRO.
Множественное наследование, super() и проблема алмаза
Давайте разберем пример использования super() для обработки порядка разрешения методов __init__ более выгодным образом. В примере мы создаем серию классов обработки текста и объединяем их функциональность в другом классе с множественным наследованием. Мы создадим 4 класса, и структура наследования будет соответствовать структуре, показанной на диаграмме ниже.
Примечание. Эта структура предназначена для иллюстративных целей, и чаще всего существуют более удачные способы реализации этой логики.

На самом деле это пример «проблемы алмаза» множественного наследования. Название проблемы связано с формой фигуры, которую образует схема наследования.
Код, представленный ниже, написан с использованием super() :
class Tokenizer: """Tokenize text""" def __init__(self, text): print('Start Tokenizer.__init__()') self.tokens = text.split() print('End Tokenizer.__init__()') class WordCounter(Tokenizer): """Count words in text""" def __init__(self, text): print('Start WordCounter.__init__()') super().__init__(text) self.word_count = len(self.tokens) print('End WordCounter.__init__()') class Vocabulary(Tokenizer): """Find unique words in text""" def __init__(self, text): print('Start init Vocabulary.__init__()') super().__init__(text) self.vocab = set(self.tokens) print('End init Vocabulary.__init__()') class TextDescriber(WordCounter, Vocabulary): """Describe text with multiple metrics""" def __init__(self, text): print('Start init TextDescriber.__init__()') super().__init__(text) print('End init TextDescriber.__init__()') td = TextDescriber('row row row your boat') print('--------') print(td.tokens) print(td.vocab) print(td.word_count)
Запустим наш код и получим следующий результат:
Start init TextDescriber.__init__() Start WordCounter.__init__() Start init Vocabulary.__init__() Start Tokenizer.__init__() End Tokenizer.__init__() End init Vocabulary.__init__() End WordCounter.__init__() End init TextDescriber.__init__() -------- ['row', 'row', 'row', 'your', 'boat'] 5
Прежде всего, мы видим, что класс TextDescriber унаследовал все атрибуты генеалогического дерева классов. Благодаря множественному наследованию мы можем объединять функциональность более чем одного класса.
Давайте теперь обсудим результаты, полученные от методов инициализации класса:
Каждый метод __init__ вызывался один и только один раз.
Класс TextDescriber унаследован от двух классов, унаследованных от Tokenizer . Почему Tokenizer.__init__ не вызывался дважды?
Если бы мы заменили все наши вызовы super() старомодным способом, мы получили бы 2 вызова Tokenizer.__init__ . Использование super() заранее «обдумывает» наш код и пропускает лишнее действие в виде двойного вызова Tokenizer.__init__ .
Каждый метод __init__ был запущен до того, как любой из других был завершен.
На порядок начала и окончания каждого __init__ стоит обращать внимание, если вы пытаетесь установить атрибут, имя которого конфликтует с другим родительским классом. Атрибут будет перезаписан, и это может все запутать.
В нашем случае мы избежали конфликтов имен с унаследованными атрибутами, поэтому все работает как положено.
Повторим еще раз: проблема алмаза может быстро все усложнить и привести к неожиданным результатам. В большинстве случаев в программировании лучше избегать сложных конструкций.
Заключение
Итак, сегодня мы поговорили про множественное наследование и super() . Мы узнали о функции super() и о том, как ее можно использовать для замены ParentName.method в одиночном наследовании. Это может быть более удобной практикой.
Также мы обсудили множественное наследование и о то, как мы можем передать функциональность нескольких родительских классов одному дочернему классу.
Кроме того, мы узнали о порядке разрешения методов MRO и о том, как он решает, что происходит при множественном наследовании, когда возникает конфликт имен между родительскими методами.
И в конце мы поговорили про проблему алмаза и увидели пример того, как использование super() взаимодействует с этой проблемой.
Объясните как работает метод super,а так-же конструкция super().__init__() в python? [закрыт]
Хотите улучшить этот вопрос? Переформулируйте вопрос так, чтобы он был сосредоточен только на одной проблеме.
Закрыт 4 года назад .
Объясните как работает метод super , а так-же конструкция super().__init__() в python? super часто используется в классах. Желательно объяснить как можно проще и на простых примерах.
Отслеживать
66.4k 6 6 золотых знаков 51 51 серебряный знак 112 112 бронзовых знаков
задан 1 июн 2019 в 12:31
366 1 1 золотой знак 3 3 серебряных знака 13 13 бронзовых знаков
1 июн 2019 в 13:05
Отличный ответ но гуглом я умею пользоваться.Читаю и разбираюсь но на данный момент понять не могу, сюда написал затем,что-бы может у кого нибудь получилось объяснить.
1 июн 2019 в 13:35
Raymond Hettinger — Super considered super! youtu.be/EiOglTERPEo
1 июн 2019 в 14:09
Нашёл такой же ролик только с русским переводом youtube.com/watch?v=61UuKJRl2m0
1 июн 2019 в 14:12
1 ответ 1
Сортировка: Сброс на вариант по умолчанию
super() — это функция, которая обращается к классу, от которого наследуется текущий.
Сначала немного кода:
class A: def some_method(self): print('Spam, eggs!!1') class B(A): def some_method(self): print('Hello, World!') x = B() x.some_method()
Hello, World!
Как Вы можете заметить, мы перегрузили метод родительского класса. Но что, если нам потребуется всего лишь немного дополнить его? Как нам дополнить родительский метод, не копируя его полностью и не изобретая велосипедов? Тут нам и нужен super() :
class A: def some_method(self): print('Spam, eggs!!1') class B(A): def some_method(self): super().some_method() print('Hello, World!') x = B() x.some_method()
Spam, eggs!!1 Hello, World!
С помощью super().some_method() мы вызвали родительский метод, а после дополнили свой. Именно для этого чаще всего используется эта функция.
__init__() — это метод инициализации класса, следовательно super().__init__() вызывает метод инициализации из родительского класса. Например, чтобы дополнить его.
