为什么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_ = 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()
在没有编译器帮助的情况下无法在运行时parsing超类? 有没有这种行为的实际情况,或者说这个行为的潜在原因,可能会让一个不小心的程序员咬牙切齿?
…作为一个侧面的问题:是否还有Python中的函数,方法等其他例子,可以通过重新绑定到不同的名称来打破?
为了避免违反DRY(不要重复自己)的原则,增加了新的魔法super()
行为,参见PEP 3135 。 不得不通过将它引用为全局来明确地命名这个类,也容易发现你用super()
本身发现的相同的重新绑定问题:
class Foo(Bar): def baz(self): return super(Foo, self).baz() + 42 Spam = Foo Foo = something_else() instance = Spam() # 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__
单元格很好地回避了这些问题,让您可以访问原始的类对象。
PEP被Guido踢开了,Guido 最初设想super
成为关键词 ,而用单元格来查看当前课程的想法也是他的 。 当然,把它作为关键词的想法是PEP初稿的一部分。
然而,实际上是Guido本人,然后脱离关键词的想法“太神奇” ,而是提出目前的实施。 他预计为super()
使用不同的名称可能是一个问题 :
我的补丁使用了一个中间解决scheme:只要您使用名为
'super'
的variables,就会假定您需要__class__
。 因此,如果你(全局)重命名super
supper
并使用supper
但不super
,它不会没有参数的工作(但它仍然会工作,如果你通过它__class__
或实际的类对象); 如果你有一个名为super
的不相关的variables,事情会起作用,但是这个方法将使用稍微慢一点的用于单元variables的调用path。
所以,最后Guido本人宣称使用super
关键字并不合适,而提供一个magic __class__
单元是一个可以接受的折衷scheme。
我同意实现的神奇,隐含的行为有点令人惊讶,但是super()
是语言中最不适用的函数之一。 只要看看互联网上发现的所有错误的super(type(self), self)
或super(self.__class__, self)
调用; 如果任何代码曾经从派生类中调用过,则最终会产生无限的recursionexception 。 至less简化的super()
调用没有参数,可以避免这个问题。
至于更名为super_
; 只需在你的方法中引用__class__
,它将再次工作。 如果在方法中使用super()
或使用__class__
,则会创build单元格:
>>> 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