关于python:为什么分配给__class__中断”super”?

Why does assigning to the __class__ cell break `super`?

我读过为什么python 3.x的super()有魔力?并理解在方法中使用super__class__将自动为该方法创建__class__单元变量:

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

据我所知,单元格用于保存闭包变量,可以自由修改:

1
2
3
4
5
6
7
8
9
10
def outer():
    x = 3
    def inner():
        print(x)

    x = 5
    return inner

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

但是试图重新分配__class__单元的值会使super产生一个奇怪的错误:

1
2
3
4
5
6
class Demo:
    def meth(self):
        __class__ = Demo
        super().meth()

Demo().meth()
1
2
3
4
5
6
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语句来分配给闭包变量,包括magic __class__闭包变量。在没有nonlocal语句的情况下分配给__class__将创建一个隐藏magic closure变量的局部变量。

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

如果您确实添加了nonlocal语句,那么实现实际上将允许您重新分配magic closure变量:

1
2
3
4
5
6
7
class Foo:
    def meth(self):
        nonlocal __class__
        __class__ = 3
        super()

Foo().meth()

结果:

1
2
3
4
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)