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. (不要重复自己)原则,见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 的一部分。 .

然而,当时stepped away from the keyword idea as 'too magical' 实际上是Guido 本人。 ,而是提出当前的实现。他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

https://stackoverflow.com/questions/19608134/

相关文章:

c - 在C中获取终端宽度?

linux - "Failed to load platform plugin "xcb ""在没有

python - 通过 Python 在 Linux 上的进程列表

python - 如何用 Python 四舍五入到小数点后两位?

python - 使用 Python 将 XML 转换为 JSON?

linux - 如何在单个命令中创建目录并授予权限

python - 检查字符串是否可以在 Python 中转换为 float

linux - 计算特定目录中的目录数

python - 如何正确使用单元测试的 assertRaises() 和 NoneType 对象?

python - 如何将 JSON 转换为 CSV?