В Python 3.x super()
можно вызывать без аргументов:
class A(object):
def x(self):
print("Hey now")
class B(A):
def x(self):
super().x()
>>> B().x()
Hey now
Для того , чтобы сделать эту работу, некоторые во время компиляции магия выполняется, следствием чего является то , что следующий код (который выполняет повторную привязку super
к super_
) не:
super_ = super
class A(object):
def x(self):
print("No flipping")
class B(A):
def x(self):
super_().x()
>>> B().x()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in x
RuntimeError: super(): __class__ cell not found
Почему super()
невозможно разрешить суперкласс во время выполнения без помощи компилятора? Существуют ли практические ситуации, в которых такое поведение или его основная причина могут укусить неосторожного программиста?
... и, как дополнительный вопрос: есть ли в Python другие примеры функций, методов и т. д., которые можно сломать, связав их с другим именем?
python
python-3.x
super
Ноль Пирей
источник
источник
Ответы:
Новое магическое
super()
поведение было добавлено, чтобы избежать нарушения принципа СУХОЙ (не повторять себя), см. PEP 3135 . Необходимость явного присвоения имени классу, ссылаясь на него как на глобальный, также подвержена тем же проблемам перепривязки, которые вы обнаружили дляsuper()
себя:То же самое относится к использованию декораторов классов, где декоратор возвращает новый объект, который связывает имя класса:
Волшебная
super()
__class__
ячейка прекрасно обходит эти проблемы, предоставляя вам доступ к исходному объекту класса.PEP был запущен Гвидо, который первоначально предполагал
super
стать ключевым словом , и идея использовать ячейку для поиска текущего класса была также его . Конечно, идея сделать это ключевым словом была частью первого проекта PEP .Однако на самом деле сам Гвидо отошел от идеи ключевого слова как «слишком волшебной» , предложив вместо этого текущую реализацию. Он ожидал, что использование другого имени для
super()
может быть проблемой :Итак, в конце концов, это был сам Гвидо, который заявил, что использование
super
ключевого слова не является правильным, и что предоставление магической__class__
ячейки было приемлемым компромиссом.Я согласен с тем, что магическое, неявное поведение реализации несколько удивительно, но
super()
является одной из наиболее неправильно примененных функций в языке. Просто взгляните на все неправильные обращенияsuper(type(self), self)
илиsuper(self.__class__, self)
обращения, найденные в Интернете; если какой-либо из этого кода будет вызван из производного класса, вы получите исключение бесконечной рекурсии . По крайней мере, упрощенныйsuper()
вызов без аргументов позволяет избежать этой проблемы.Что касается переименованных
super_
; просто ссылаться__class__
на ваш метод , а также , и он будет работать снова. Ячейка создается, если вы ссылаетесь на именаsuper
или__class__
в вашем методе:источник
def super(of_class=magic __class__)
вроде aself.super(); def super(self): return self.__class__
?super()
без аргументов работает; это главным образом имеет дело с тем, почему это существует.super()
в методе класса эквивалентноsuper(ReferenceToClassMethodIsBeingDefinedIn, self)
, гдеReferenceToClassMethodIsBeingDefinedIn
определяется во время компиляции, присоединяется к методу как именованное замыкание__class__
иsuper()
будет искать оба из вызывающего фрейма во время выполнения. Но вам на самом деле не нужно знать все это.super()
это далеко не автоматическая функция , нет.__class__
в своем методе . Вы использовали имяsuper
в своей функции. Компилятор видит это и добавляет__class__
закрытие.type(self)
дает текущий тип, который не совпадает с типом, для которого определен метод. Таким образом, классFoo
с методомbaz
нуждаетсяsuper(Foo, self).baz()
, потому что он может быть разделен на подклассыclass Ham(Foo):
, в какой точкеtype(self)
находитсяHam
иsuper(type(self), self).baz()
даст вам бесконечный цикл. См. Пост, на который я ссылаюсь в своем ответе: при вызове super () в производном классе могу ли я передать self .__ class__?