161

在 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

为了完成这项工作,执行了一些编译时魔法,其结果之一是以下代码(重新绑定supersuper_)失败:

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 中是否还有其他函数、方法等示例可以通过将它们重新绑定到不同的名称来破坏?

4

1 回答 1

224

添加了新的魔术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__单元通过让您访问原始类对象很好地回避了这些问题。

PEP 是由 Guido 启动的,他最初设想super成为关键字,使用单元格查找当前班级的想法也是他的。当然,将其作为关键字的想法是PEP 初稿的一部分。

然而,实际上是 Guido 本人随后因为“太神奇”而放弃了关键字想法,而是提出了当前的实施方案。他预计使用不同的名称super()可能是一个问题

我的补丁使用了一种中间解决方案:它假定您__class__ 在使用名为'super'. 因此,如果您(全局)重命名supersupper并使用supperbut not 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
于 2013-10-26T16:41:24.223 回答