为什么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