python - 为什么 Python 3.x 的 super() 如此神奇?

标签 python python-3.x super

在 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 重新绑定(bind)到 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() 在没有编译器帮助的情况下无法在运行时解析父类(super class)?是否存在这种行为或其潜在原因可能会影响粗心的程序员的实际情况?

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

最佳答案

添加了新的魔法 super() 行为以避免违反 D.R.Y. (Don't Repeat Yourself)原理,见PEP 3135 .必须通过将其作为全局引用来显式命名该类也容易出现与 super() 本身发现的相同的重新绑定(bind)问题:

class Foo(Bar):
    def baz(self):
        return super(Foo, self).baz() + 42

Spam = Foo
Foo = something_else()

Spam().baz()  # liable to blow up

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

@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 发起,他 initially envisioned super becoming a keyword ,以及使用单元格查找当前类的想法 was also his .当然,将其作为关键字的想法是 first draft of the PEP 的一部分。 .

然而,实际上是 Guido 自己stepped away from the keyword idea as 'too magical' ,而不是提出当前的实现。他anticipated that using a different name for super() could be a problem :

My patch uses an intermediate solution: it assumes you need __class__ whenever you use a variable named 'super'. Thus, if you (globally) rename super to supper and use supper but 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.

所以,最后,是 Guido 自己宣称使用 super 关键字感觉不对,提供一个神奇的 __class__ 单元格是一个可以接受的妥协.

我同意实现的神奇、隐式行为有些令人惊讶,但 super() 是该语言中最常被误用的函数之一。看看所有被误用的super(type(self), self)super(self.__class__, self)在 Internet 上找到的调用;如果从派生类中调用过任何代码 you'd end up with an infinite recursion exception .至少,没有参数的简化 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

关于python - 为什么 Python 3.x 的 super() 如此神奇?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48691652/

相关文章:

Python3 的 super 和 comprehensions -> TypeError?

python - 获取matplotlib中矩形选择的数据

python - 如何使用 python 从非结构化 HTML 创建结构化数组

python - 过滤字符串列表以不包含来自另一个列表的任何字符串作为子字符串

python - 将嵌套在两个字典下的列表转换为 DataFrame

Python单元测试内存消耗

java - 为什么这里的 super 引用的地址与引用变量 sc1 引用的地址相同?

python - Python 3 中的 super() 是如何实现的?

python - Python中重载构造函数的要点?

python - 如何获取检测到的物体的类别 - tensorflow