Почему Python 3.супер () магия x?
В 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 функции, методы и т. д. что может быть нарушено путем повторной привязки их к другому имени?
1 ответ:
новая магия
super()
поведение было добавлено, чтобы избежать нарушения принципа D. R. Y. (не повторяйтесь), см. PEP 3135. Необходимость явно называть класс, ссылаясь на него как на глобальный, также подвержена тем же проблемам с повторной привязкой, которые вы обнаружили с помощью :class Foo(Bar): def baz(self): return super(Foo, self).baz() + 42 Spam = Foo Foo = something_else() Spam().baz() # liable to blow up
то же самое относится к использованию декораторов классов, где декоратор возвращает новый объект, который повторно связывает имя класса:
@class_decorator_returning_new_class class Foo(Bar): def baz(self): # Now `Foo` is a *different class* return super(Foo, self).baz() + 42
магия
super()
__class__
ячейка обходит эти проблемы красиво, предоставляя вам доступ к исходному объекту класса.бодрость духа был сброшен Гвидо, который первоначально envisioned
super
становится ключевым словом, и идея использования ячейки для поиска текущего класса и. Конечно, идея сделать его ключевым словом была частью первый проект ОПТОСОЗ.однако на самом деле это был сам Гвидо, который тогда отошел от ключевое слово идея как "слишком волшебный", предлагая вместо этого текущую реализацию. Он ожидал, что использование другого имени для
super()
может быть проблема:мой патч использует промежуточное решение: он предполагает, что вам нужно
__class__
всякий раз, когда вы используете переменную'super'
. Таким образом, если вы (глобально) переименоватьsuper
доsupper
и использоватьsupper
а неsuper
, это не сработает без аргументов (но он все равно будет работать, если вы передаете его либо__class__
или фактический объект класса); если у вас есть несвязанный переменная с именемsuper
, все будет работать, но метод будет использовать немного более медленный путь вызова, используемый для переменных ячейки.так, в конце концов, это был сам Гвидо, который объявил, что с помощью
super
ключевое слово не чувствовалось правильным, и это обеспечивало магию__class__
клетка была приемлемым компромиссом.я согласен, что магия, неявное поведение реализации несколько удивительно, но
super()
является одной из самых неправильно применяемых функций в языке. Просто взгляните на все неправильноsuper(type(self), self)
илиsuper(self.__class__, self)
вызовы, найденные в интернете; если какой-либо из этого кода когда-либо вызывался из производного класса вы бы в конечном итоге с бесконечной рекурсии исключением. По крайней мере, упрощенныйsuper()
вызов, без аргументов, избегает это проблема.что касается переименована
super_
; просто ссылка__class__
в методе а также и это будет работать снова. Ячейка создается, если вы ссылаетесь либоsuper
или__class__
имена в свой метод:>>> super_ = super >>> class A(object): ... def x(self): ... print("No flipping") ... >>> class B(A): ... def x(self): ... __class__ # just referencing it is enough ... super_().x() ... >>> B().x() No flipping