Python super init что это
Подробно про метод super() в Python
Сегодня в этом руководстве мы обсудим метод super() в Python. Перед тем, как погрузиться в тему, мы настоятельно рекомендуем изучить руководство по наследованию Python.
super метод возвращает прокси-объект, который делегирует вызовы методов родительскому или одноуровневому классу типа. Это полезно для доступа к унаследованным методам, которые были переопределены в классе.
Или просто он используется для вызова конструктора, то есть метода __init__() суперкласса.
В версиях Python 3.x мы можем использовать super без передачи двух вышеуказанных параметров. Посмотрите на приведенный ниже фрагмент кода.
Как видите, строка super().method(arg) super( C, self).method(arg) фактически эквивалентна super( C, self).method(arg) в Python 3.x. Это запрещено в Python 2.x. Следовательно, использовать super там сложно.
Использование super()
Рассмотрим приведенный ниже пример.
В приведенном выше примере классы, производные от базового класса Demo не были реализованы эффективно или надежно.
Этот процесс неэффективен. Это означает, что подклассу должен быть предоставлен доступ к членам суперкласса.
Super() для вызова конструктора суперкласса
Теперь применим метод super() к приведенному выше примеру.
Использование super в Python 2.x
Синтаксис для вызова конструктора super в Python 2.x приведен ниже.
Следовательно, нам нужно внести некоторые незначительные изменения в приведенный выше пример, если мы хотим использовать его в Python 2.
Во-первых, нам нужно поместить object в базовый класс, как показано ниже.
А во-вторых, пройти Newdemo и self на месте вызова суперкласса. Нравится.
Зачем нужен super()
В случае одиночного наследования с родительским и дочерним классами super используется для неявной ссылки на родительский класс без его явного имени. Это делает код более эффективным, удобным в обслуживании и надежным по своей природе.
Далее, для многоуровневого наследования super может использоваться для неявной ссылки на непосредственный суперкласс. Это снова упрощает понимание кода и упрощает обслуживание.
andGINEER
Andrey Sorokin, engineer
Множественное наследование
Python позволяет указать для класса несколько родителей. Это называется множественным наследованием.
Например, мы хотим добавить какие-то общие свойства нескольким разным классам. Добавлять эти свойства, через класс-наследник для каждого из классов явно некрасиво, нарушает принцип DRY.
Если речь о чем-то простом, то это можно сделать через декоратор. Но если это что-то более развесистое и прикладное, то напрашивается оформить это как объект, и добавить к нужным классам как mixin. В Python нет специального способа добавлять mixin, это осуществляется через множественное наследование.
Загадка
Кстати, если быть занудой, то утконос это млекопитающее, обладающее также свойствами рептилиии. Но рептилии скользкие и холодные, и мне показалось более уютно заменить их на птиц 😉
Проблема ромбов при множественном наследовании
Описанная выше загадка относится к “проблеме ромбов” (diamond problem), она всегда возникает при множественном наследовании, не только в Python.
Если у класса есть несколько родителей, а у родителей есть общий предок, получаем ромб в дереве наследования, как видно на диаграмме.
Алгоритм C3 поиска в дереве наследования классов Python 3 (MRO)
Для поиска методов и полей в дереве родителей (MRO), Python использует C3 алгоритм.
Совсем упрощенно C3 алгоритм MRO можно представить так:
в список добавляются родители объекта
если какой-то класс оказывается в списке дважды, то оставляется только последнее его вхождение.
Как результат, мы движемся по слоям, не обращаемся к классу-предку до того, как обратимся ко всем его потомкам, даже если потомков у этого предка несколько.
Алгоритм обеспечивает поиск переопределенного метода класса-предка, если этот метод переопределен хотя бы в одном потомке этого класса-предка.
И в любом случае это привело бы к неочевидному поведению и невозможности переопределять в более чем одном родителе методы object (и прикладных объектов, для которых возникает ситуация ромбов).
Функция super()
Функция super() обеспечивает так называемое “кооперативное” наследование методов. Если во всех переопределенных методах использовать эту функцию, то она обеспечит вызов методов всех классов по алгоритму MRO.
super() это не класс-родитель, это объект, позволяющий вызвать следующий по
алгоритму MRO класс.
Это может привести к изменению поведения класса, если мы его добавляем в дерево наследования. Он начнет вызывать метод не родителя, как делал, когда не был добавлен в дерево множественного наследования, а другого класса, который переопределил метод родителя.
Иллюстрация кооперативного множественного наследования с помощью super()
Если хоть один наследник нарушает принципы кооперативного наследования (не вызывает super() ), то метод родителя вообще не будет вызван, хотя вроде бы мы имеем явный вызов этого родителя из другого наследника.
Например, давайте закомментарим вызов super() в классе Bird (строка 8). Вывод изменится следующим образом:
Одним из ограничений super() является то, что не получится выполнить операции (binary operations, subscriptions и т.д.) над возвращенным объектом, даже если эти операции реализованы в родителе вызывающего класса с помощью “магических методов”.
super() – супер класс в Python
super() – это встроенная функция языка Python. Она возвращает прокси-объект, который делегирует вызовы методов классу-родителю (или собрату) текущего класса (или класса на выбор, если он указан, как параметр).
Основное ее применение и польза – получения доступа из класса наследника к методам класса-родителя в том случае, если наследник переопределил эти методы.
Что такое прокси-объект? Прокси, по-русски, это заместитель. То есть это объект, который по смыслу должен вести себя почти так же, как замещенный объект. Как правило он перенаправляет вызовы своих методов к другому объекту.
Давайте рассмотрим пример наследования. Есть какой-то товар в классе Base с базовой ценой в 10 единиц. Нам понадобилось сделать распродажу и скинуть цену на 20%. Хардкодить – это непрофессионально и негибко:
Здесь, надо не забыть указать self при вызове первым параметром явно, чтобы метод был привязан к текущему объекту. Это будет работать, но этот код не лишен изъянов, потому что необходимо явно указывать имя предка. Представьте, если иерархия классов начнет разрастаться? Например, нам нужно будет вставить между этими классами еще один класс, тогда придется редактировать имя класса-родителя в методах Discount:
Будучи вызванным без параметров внутри какого-либо класса, super() вернет прокси-объект, методы которого будут искаться только в классах, стоящих ранее, чем он, в порядке MRO. То есть, это будет как будто бы тот же самый объект, но он будет игнорировать все определения из текущего класса, обращаясь только к родительским:
Когда нельзя забыть super?
Очень часто super вызывается в методе __init__. Метод инициализации класса __init__, как правило задает какие-либо атрибуты экземпляра класса, и если в дочернем классе мы забудем его вызвать, то класс окажется недоинициализированным: при попытке доступа к родительским атрибутам будет ошибка:
Параметры super
Теперь Python достаточно умен, чтобы самостоятельно подставить в аргументы текущий класс и self для привязки. Но старая форма тоже осталась для особых случаев. Она нужна, если вы используете super() вне класса или хотите явно указать с какого класса хотите начать поиск методов.
Действительно, super() может быть использована вне класса. Пример:
В этом случае объект, полученный из super(), будет вести себя как класс InterFoo (родитель Discount), хотя привязан он к переменной d, которая является экземпляром класса Discount.
Это редко используется, но, вероятно, кому-то будет интересно узнать, что функция super(cls), вызванная только с одним параметром, вернет непривязанный к экземпляру объект. У него нельзя вызывать методы и обращаться к атрибутам. Привязать его можно будет так:
Множественное наследование
В случае множественного наследования super() необязательно указывает на родителя текущего класса, а может указывать и на собрата. Все зависит от структуры наследования и начальной точки вызова метода. Общий принцип остается: поиск начинается с предыдущего класса в списке MRO. Давайте рассмотрим пример ромбовидного наследования. Каждый класс ниже в методе method печатает свое имя. Плюс все, кроме первого, вызывают свой super().method() :
Таким образом, вызов super() сам автоматически догадывается, к кому обращаться: к родителю или к брату. Все зависит от иерархии класса и начальной точки вызова. Эта фишки снимают с программиста головную боль, связанную с заботой о поддержании цепочки вызовов в иерархии классов.
Специально для канала @pyway. Подписывайтесь на мой канал в Телеграм @pyway 👈
Функция super() в Python
Функция super() в Python позволяет нам явно ссылаться на родительский класс. Это полезно в случае наследования, когда мы хотим вызывать функции суперкласса. В Python Inheritance подклассы наследуются от суперкласса.
Функция super() позволяет нам неявно ссылаться на суперкласс. Итак, super делает нашу задачу проще и удобнее. Ссылаясь на суперкласс из подкласса, нам не нужно явно писать имя суперкласса.
Пример функции
Сначала просто посмотрите на следующий код, который мы использовали в нашем руководстве по наследованию. В этом примере кода суперклассом был Person, а подклассом – Student. Итак, код показан ниже.
В приведенном выше примере мы вызвали функцию родительского класса, как:
Мы можем заменить это вызовом функции, как показано ниже:
Результат останется таким же в обоих случаях, как показано на изображении ниже:
Функция для Python 3
Обратите внимание, что приведенный выше синтаксис предназначен для функции super() в python 3. Если вы используете версию Python 2.x, она немного отличается, и вам придется внести следующие изменения:
Первое изменение – сделать объект базовым классом для Person. В версиях Python 2.x необходимо использовать функцию super. В противном случае вы получите следующую ошибку:
Второе изменение синтаксиса самой функции. Как видите, функция в python 3 намного проще в использовании, и синтаксис также выглядит чистым.
Функция super() с многоуровневым наследованием
Как мы уже заявляли ранее, super() позволяет нам неявно ссылаться на суперкласс.
Но в случае многоуровневого наследования, к какому классу оно будет относиться? super() всегда будет ссылаться на непосредственный суперкласс.
Также функция может не только ссылаться на функцию __init __(), но также может вызывать все другие функции суперкласса. Итак, в следующем примере мы увидим это:
Давайте посмотрим на результат вышеприведенного примера в python 3 с многоуровневым наследованием.
Итак, из выходных данных мы ясно видим, что сначала была вызвана функция __init __() класса C, затем класса B, а затем класса A. Аналогичная вещь произошла при вызове функции sub_method().
Зачем нужна функция super()?
Если у вас есть предыдущий опыт работы с языком Java, вы должны знать, что базовый класс также вызывается там супер объектом. Итак, эта концепция действительно полезна для кодеров. Однако Python также позволяет программисту использовать имя суперкласса для ссылки на него. И, если ваша программа содержит многоуровневое наследование, эта функция будет вам полезна.
Функция super() в Python, доступ к унаследованным методам.
Обеспечивает доступ к оригиналам наследованных методов.
Синтаксис:
Параметры:
Возвращаемое значение:
Описание:
Типичные случаи использования super() :
В иерархиях с единичным наследованием используется для обращения к родительским классам, чтобы явно не указывать их имена, это упрощает поддержку кода в дальнейшем. Еще примеры.
Здесь перегружен метод родительского класса. Но что, если необходимо немного дополнить родительский метод, не копируя его полностью? Тут и нужна функция super() :
Для поддержки совместного множественного наследования в динамическом окружении. Он делает возможным обращение с ромбовидными иерархиями, при которых несколько базовых классов задают реализацию метода с одним и тем же именем.
Использование функция super() с обоими аргументами точно определяет объекты и делает соответствующие ссылки. Без аргументов функция super() работает только внутри определения класса, а необходимые детали для идентификации класса и доступа к текущему экземпляру для методов заполняет компилятор.
В дополнение к поиску методов, super() также работает для поиска атрибутов. Одним из вариантов использования этого является вызов дескрипторов в родительском или родственном классе.
Примеры получения доступа к унаследованным методам.
Функция в единичном наследовании:
И наконец пример работы функции super() при использовании множественного наследования: