Понимание 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-orientedChildA
- нет: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 классов. Если вы скажете oosuper
, что мы находимся в методе 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
Понимание Python super() с помощью методов __init __()
Мы используем файлы cookies для улучшения работы сайта. Оставаясь на нашем сайте, вы соглашаетесь с условиями использования файлов cookies. Чтобы ознакомиться с нашими Положениями о конфиденциальности и об использовании файлов cookie, нажмите здесь.