python - 为什么分配给 __class__ 单元格会中断 `super` ?

标签 python closures super

我已阅读 Why is Python 3.x's super() magic?并了解在方法中使用 super__class__ 会自动为该方法创建一个 __class__ 单元格变量:

class Demo:
    def meth(self):
        super().meth()
>>> Demo.meth.__closure__
(<cell at 0x7f4572056138: type object at 0x564bda0e5dd8>,)
>>> Demo.meth.__closure__[0].cell_contents
<class '__main__.Demo'>

据我所知,cell是用来保存闭包变量的,并且可以自由修改:

def outer():
    x = 3
    def inner():
        print(x)

    x = 5
    return inner

inner = outer()
inner()  # output: 5
>>> inner.__closure__
(<cell at 0x7f2183a5e138: int object at 0x7f2184600460>,)

但是尝试重新分配 __class__ 单元格的值会使 super 抛出一个奇怪的错误:

class Demo:
    def meth(self):
        __class__ = Demo
        super().meth()

Demo().meth()
Traceback (most recent call last):
  File "untitled.py", line 8, in <module>
    Demo().meth()
  File "untitled.py", line 6, in meth
    super().meth()
RuntimeError: super(): __class__ cell not found

为什么会发生这种情况?为什么__class__不能像其他闭包变量一样重新赋值?

最佳答案

您需要一个 nonlocal 语句来分配给闭包变量,包括神奇的 __class__ 闭包变量。在没有 nonlocal 语句的情况下分配给 __class__ 会创建一个隐藏魔术闭包变量的局部变量。

您期望 __class__ 的行为就像它是 meth 的本地行为一样,但实际上它的行为就像它是一个不可见的伪作用域的本地行为,其中所有方法都在其中Demo 是嵌套的。如果它被视为 meth 本地的,则不需要 nonlocal

如果您确实添加了 nonlocal 语句,则实现 actually will allow you重新分配魔术闭包变量:

class Foo:
    def meth(self):
        nonlocal __class__
        __class__ = 3
        super()

Foo().meth()

结果:

Traceback (most recent call last):
  File "./prog.py", line 7, in <module>
  File "./prog.py", line 5, in meth
RuntimeError: super(): __class__ is not a type (int)

关于python - 为什么分配给 __class__ 单元格会中断 `super` ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52429844/

相关文章:

java - Exception 子类中 `Super` 关键字的影响

python - M2Crypto:从不透明签名的 S/MIME (pkcs7-mime) 中提取消息

python - 词法闭包是如何工作的?

javascript - React hooks - 由于关闭而异步 setState 更新旧状态

c++ - C 的替代方案,例如为 C++ 标记和转义嵌套循环

python - 在不重写方法的子类中调用 super().method()

python - 在 Cython 中声明 FILE 指针

python - 在 Python 中对 JSON 文件进行排序并输出为 Excel

python - 为什么 IDLE 3.4 在这个程序上花费这么长时间?

python - 让 super() 在 Python 中工作 urllib2.Request