Я прочитал Почему в Python 3.x есть магия super ()? и понимаю, что использование 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'>
И, насколько мне известно, ячейки используются для хранения закрывающих переменных и могут быть свободно изменены:
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__. Назначение __class__ без оператора nonlocal создает локальную переменную, которая скрывает переменную магического закрытия.
Вы ожидаете, что __class__ будет вести себя так, как если бы он был локальным по отношению к meth, но на самом деле он ведет себя так, как если бы он был локальным по отношению к невидимой псевдо-области, в которую вложены все методы Demo. Если бы он рассматривался как локальный для meth, вам не понадобился бы nonlocal.
Если вы действительно добавите оператор nonlocal, реализация на самом деле позволит вам для переназначения переменной магического закрытия:
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)
Это назначение обсуждается в ответе пользователя2357112 здесь: «Назначение
__class__означает, что__class__является локальной переменной, а не закрывающей переменной». Дупить?