Почему присвоение ячейке __class__ прерывает `super`? - PullRequest
0 голосов
/ 20 сентября 2018

Я прочитал Почему в 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__ переназначить как другие переменные замыкания?

1 Ответ

0 голосов
/ 20 сентября 2018

Вам необходим оператор 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)
...