为什么 Python 3.x 的 super() 很神奇?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/19608134/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-19 14:09:54  来源:igfitidea点击:

Why is Python 3.x's super() magic?

pythonpython-3.xsuper

提问by Zero Piraeus

In Python 3.x, super()can be called without arguments:

在 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

In order to make this work, some compile-time magic is performed, one consequence of which is that the following code (which rebinds superto super_) fails:

为了使这项工作,一些编译时魔术被执行,其后果之一是以下代码(重新绑定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

Why is super()unable to resolve the superclass at runtime without assistance from the compiler? Are there practical situations in which this behaviour, or the underlying reason for it, could bite an unwary programmer?

为什么super()在没有编译器帮助的情况下无法在运行时解析超类?是否存在这种行为或其根本原因可能会咬到粗心的程序员的实际情况?

... and, as a side question: are there any other examples in Python of functions, methods etc. which can be broken by rebinding them to a different name?

......而且,作为一个附带问题:Python 中是否还有其他函数、方法等示例可以通过将它们重新绑定到不同的名称来破坏?

采纳答案by Martijn Pieters

The new magic super()behaviour was added to avoid violating the D.R.Y. (Don't Repeat Yourself) principle, see PEP 3135. Having to explicitly name the class by referencing it as a global is also prone to the same rebinding issues you discovered with super()itself:

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

The same applies to using class decorators where the decorator returns a new object, which rebinds the class name:

这同样适用于使用类装饰器,其中装饰器返回一个新对象,它重新绑定类名:

@class_decorator_returning_new_class
class Foo(Bar):
    def baz(self):
        # Now `Foo` is a *different class*
        return super(Foo, self).baz() + 42

The magic super()__class__cell sidesteps these issues nicely by giving you access to the original class object.

super()__class__通过让您访问原始类对象,魔法单元很好地回避了这些问题。

The PEP was kicked off by Guido, who initially envisioned superbecoming a keyword, and the idea of using a cell to look up the current class was also his. Certainly, the idea to make it a keyword was part of the first draft of the PEP.

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

However, it was in fact Guido himself who then stepped away from the keyword idea as 'too magical', proposing the current implementation instead. He anticipated that using a different name for super()could be a problem:

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

My patch uses an intermediate solution: it assumes you need __class__whenever you use a variable named 'super'. Thus, if you (globally) rename superto supperand use supperbut not super, it won't work without arguments (but it will still work if you pass it either __class__or the actual class object); if you have an unrelated variable named super, things will work but the method will use the slightly slower call path used for cell variables.

我的补丁使用了一个中间解决方案:它假设您__class__在使用名为'super'. 因此,如果您(全局)重命名supersupper并使用supper但不使用super,则它在没有参数的情况下将无法工作(但如果您传递它__class__或实际的类对象,它仍然可以工作 );如果您有一个不相关的变量名为super,事情会起作用,但该方法将使用用于单元格变量的稍慢的调用路径。

So, in the end, it was Guido himself that proclaimed that using a superkeyword did not feel right, and that providing a magic __class__cell was an acceptable compromise.

所以,最后是圭多自己宣称使用super关键字感觉不对,提供魔法__class__电池是可以接受的妥协。

I agree that the magic, implicit behaviour of the implementation is somewhat surprising, but super()is one of the most mis-applied functions in the language. Just take a look at all the misapplied super(type(self), self)or super(self.__class__, self)invocations found on the Internet; if any of that code was ever called from a derived class you'd end up with an infinite recursion exception. At the very least the simplified super()call, without arguments, avoids thatproblem.

我同意该实现的神奇、隐式行为有点令人惊讶,但它super()是该语言中最被误用的函数之一。只需看看 互联网上发现的所有误用super(type(self), self)super(self.__class__, self)调用;如果从派生类中调用过任何代码,您最终会遇到无限递归异常。至少super(),没有参数的简化调用避免了这个问题。

As for the renamed super_; just reference __class__in your method as welland it'll work again. The cell is created if you reference either the superor__class__names in your method:

至于改名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