Почему присвоение ячейке __class__ прерывает `super`?

1

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

  • 0
    Связанный
  • 1
    Это назначение обсуждается в ответе user2357112 здесь : «Назначение __class__ означает, что __class__ является локальной переменной вместо закрывающей переменной». Dupe?
Теги:
closures
super

1 ответ

2
Лучший ответ

Вам нужно 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)

Ещё вопросы

Сообщество Overcoder
Наверх
Меню