在Python 3.x中,super()可以不带参数调用:
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_
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中是否还有其他函数,方法等示例,可以通过将它们重新绑定为其他名称来破坏它们吗?
super()添加了新的魔术行为,以避免违反DRY(请勿重复自己)原理,请参阅PEP 3135。必须通过将其引用为全局来显式地命名该类,这也容易产生与你自己发现的相同的重新绑定问题super():
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__单元使你可以访问原始类对象,从而很好地避开了这些问题。
super() __class__
PEP由Guido发起,他最初设想super成为关键字,并且使用单元格查找当前班级的想法也是他的想法。当然,使其成为关键字的想法是PEP初稿的一部分。
Guido
但是,实际上是Guido自己才放弃了“太不可思议”的关键字概念,而是提出了当前的实现方式。他预计使用其他名称super()可能会出现问题:
我的补丁使用了一种中间解决方案:假定你__class__每次使用名为的变量时都需要使用'super'。因此,如果你(全局)重新命名super,以supper和使用supper,但不能super,也不会不带参数的工作(但它仍然可以工作,如果你通过它要么 __class__或实际的类对象); 如果你有一个名为的不相关变量super,那么一切都会起作用,但是该方法将使用稍慢一些的用于单元变量的调用路径。
__class__
'super'
因此,最终,Guido自己宣布使用super关键字感觉不正确,并且提供一个魔术__class__单元是可以接受的折衷方案。
我同意该实现的神奇的,隐式的行为有些令人惊讶,但它super()是该语言中最常被错误使用的功能之一。只需看看 Internet上所有被误用super(type(self), self)或super(self.__class__, self)调用的内容;如果从派生类调用了任何代码,最终都会遇到无限递归异常。至少super()没有参数的简化调用可以避免该问题。
super(type(self), self)
super(self.__class__, self)
至于更名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