Понимание Python super() с помощью методов __init __()

Я пытаюсь понять super()

Причина, по которой мы используем super super, заключается в том, что object-oriented дочерние классы, которые class могут использовать кооперативное inheritance множественное наследование, будут classes вызывать правильную функцию classes следующего родительского object-oriented класса в порядке разрешения oop методов (MRO).

В Python 3 python-interpreter мы можем называть это так:

class ChildB(Base):
    def __init__(self):
        super().__init__()

В python-interpreter Python 2 от нас требовалось inherit вызвать super, как это, с именем inheritence определяющего класса и self, но super с этого момента мы будем super избегать этого, потому что inherit это избыточно, медленнее class (из-за поиска имени) и более oo подробный (так что обновите inheritence свой Python, если вы еще oops этого не сделали!):

        super(ChildB, self).__init__()

Без super inheritance вы ограничены в своей возможности oo использовать множественное inheritance наследование, потому что oops вы жестко подключаете следующий inheritence родительский вызов:

        Base.__init__(self) # Avoid this.

Я объясню inheritance подробнее ниже.

«Какая разница на самом деле в этом коде ?:»

class ChildA(Base):
    def __init__(self):
        Base.__init__(self)

class ChildB(Base):
    def __init__(self):
        super().__init__()

Основное отличие python-shell этого кода состоит в том, что object-oriented в ChildB вы получаете уровень косвенного oop обращения в __init__ с super, который classes использует класс, в котором inheritance он определен, для определения oo __init__ следующего класса для поиска object-oriented вверх в MRO.

Я иллюстрирую oops эту разницу в ответе на canonical question, How to use 'super' in Python?, где pythonic демонстрируются внедрение зависимостей и совместное множественное наследование.

Если в Python не было super

Вот код, который python-interpreter на самом деле очень похож object-oriented-design на super (как он реализован в class C, за исключением некоторых object-oriented проверок и отката, и переведен python на Python):

class ChildB(Base):
    def __init__(self):
        mro = type(self).mro()
        check_next = mro.index(ChildB) + 1 # next after *this* class.
        while check_next < len(mro):
            next_class = mro[check_next]
            if '__init__' in next_class.__dict__:
                next_class.__init__(self)
                break
            check_next += 1

Написан немного class больше как нативный Python:

class ChildB(Base):
    def __init__(self):
        mro = type(self).mro()
        for next_class in mro[mro.index(ChildB) + 1:]: # slice to end
            if hasattr(next_class, '__init__'):
                next_class.__init__(self)
                break

Если oo бы у нас не было объекта class super, нам пришлось бы писать object-oriented этот ручной код везде (или inherit воссоздавать его!), чтобы class гарантировать, что мы вызываем object-oriented-design правильный следующий метод super в порядке разрешения методов!

Как oo super делает это в Python py 3 без явного указания класса inherit и экземпляра метода, из которого class он был вызван?

Он получает classes кадр вызывающего стека и class находит класс (неявно сохраненный python-interpreter как локальная свободная переменная, __class__, что inheritence делает вызывающую функцию python-shell закрытием класса) и первый python-shell аргумент этой функции, который inheritence должен быть экземпляром или class класс, который сообщает ему, какой python порядок разрешения методов python (MRO) использовать.

Поскольку classes для MRO требуется этот первый object-oriented аргумент, using super with static methods is impossible as they do not have access to the MRO of the class from which they are called.

Критика других ответов:

super() позволяет oo избежать явного обращения oops к базовому классу, что может inheritence быть неплохо. . Но главное oop преимущество заключается py в множественном наследовании, где py могут происходить всевозможные class забавы. См. Стандартные документы object-oriented по super, если вы еще этого oop не сделали.

Это довольно непросто oops и мало что говорит нам, но object-oriented суть super не в том, чтобы избежать inheritence написания родительского класса. Дело inheritance в том, чтобы гарантировать, что super вызывается следующий метод class в очереди в порядке разрешения oop методов (MRO). Это становится python важным при множественном python-shell наследовании.

Я объясню здесь.

class Base(object):
    def __init__(self):
        print("Base init'ed")

class ChildA(Base):
    def __init__(self):
        print("ChildA init'ed")
        Base.__init__(self)

class ChildB(Base):
    def __init__(self):
        print("ChildB init'ed")
        super().__init__()

И py давайте создадим зависимость, которую classes мы хотим вызывать после Child:

class UserDependency(Base):
    def __init__(self):
        print("UserDependency init'ed")
        super().__init__()

Теперь python-shell помните, ChildB использует super, а object-oriented ChildA - нет:

class UserA(ChildA, UserDependency):
    def __init__(self):
        print("UserA init'ed")
        super().__init__()

class UserB(ChildB, UserDependency):
    def __init__(self):
        print("UserB init'ed")
        super().__init__()

И UserA не вызывает метод python-shell UserDependency:

>>> UserA()
UserA init'ed
ChildA init'ed
Base init'ed
<__main__.UserA object at 0x0000000003403BA8>

Но UserB фактически inheritance вызывает UserDependency, потому inheritance что ChildB вызывает super:

>>> UserB()
UserB init'ed
ChildB init'ed
UserDependency init'ed
Base init'ed
<__main__.UserB object at 0x0000000003403438>

Критика другого ответа

Ни при каких inheritence обстоятельствах вы не должны class делать следующее, что предлагает py другой ответ, так как вы inheritence обязательно получите ошибки oop при создании подкласса ChildB:

super(self.__class__, self).__init__()  # DON'T DO THIS! EVER.

(Этот ответ не является умным или особенно интересным, но, несмотря на прямую критику в комментариях и более 17 отрицательных голосов, ответчик упорно предлагал его, пока добрый редактор не исправил его проблему.)

Explanation: Использование pythonic self.__class__ вместо имени класса в super() приведет python к рекурсии. super позволяет нам oops искать следующего родителя classes в MRO (см. первый раздел oo этого ответа) для дочерних oo классов. Если вы скажете oo super, что мы находимся в методе super дочернего экземпляра, он oop затем найдет следующий метод object-oriented в строке (возможно, этот), что super приведет к рекурсии, что, вероятно, вызовет oo логический сбой (в примере inheritence ответчика, это так) или RuntimeError при oop превышении глубины рекурсии.

>>> class Polygon(object):
...     def __init__(self, id):
...         self.id = id
...
>>> class Rectangle(Polygon):
...     def __init__(self, id, width, height):
...         super(self.__class__, self).__init__(id)
...         self.shape = (width, height)
...
>>> class Square(Rectangle):
...     pass
...
>>> Square('a', 10, 10)
Traceback (most recent call last):
  File "", line 1, in 
  File "", line 3, in __init__
TypeError: __init__() missing 2 required positional arguments: 'width' and 'height'

Новый python-interpreter метод вызова super() Python 3 без inheritence аргументов, к счастью, позволяет python-shell нам обойти эту проблему.

python

class

oop

inheritance

super

2022-11-18T07:07:29+00:00
Вопросы с похожей тематикой, как у вопроса:

Понимание Python super() с помощью методов __init __()