«Локальная переменная, на которую ссылаются до назначения» – только функции?

Возьмите следующий код:

import something def Foo(): something = something.SomeClass() return something 

… это, видимо, недействительный код:

 UnboundLocalError: local variable 'something' referenced before assignment 

… поскольку локальная переменная something создается, но не назначается, прежде чем оценивается RHS = . (См., Например, комментарий этого смежного ответа .) Это кажется немного странным для меня, но я уверен, что я пойду с ним. Теперь, почему следующий допустимый код?

 class Foo(object): something = something.SomeClass() 

Мое понимание заключалось в том, что внутреннее определение class было по существу областью:

Затем пакет класса выполняется в новом кадре выполнения (см. Раздел «Именование и привязка»), используя недавно созданное локальное пространство имен и исходное глобальное пространство имен.

Итак, почему этот код действует иначе, чем функция?

Из документации класса python :

Определения классов помещают еще одно пространство имен в локальную область.

Особая причуда Python заключается в том, что – если глобальный оператор не действует, назначения имен всегда переходят в самую внутреннюю область. Присвоения не копируют данные – они просто связывают имена с объектами. То же самое верно и для делеций: оператор del x удаляет привязку x из пространства имен, на которое ссылается локальная область. Фактически, все операции, которые вводят новые имена, используют локальную область действия: в частности, операторы импорта и определения функций связывают имя модуля или функции в локальной области. (Глобальный оператор может использоваться для указания того, что определенные переменные живут в глобальной области.)

Таким образом, внутри функции (или области) присваивание создает локальную несвязаемую переменную, к которой обращаются до ее привязки, тогда как в определении класса она создает запись в словаре имен пространства этого класса при назначении, что позволяет разрешить что- something к внешнему пространству имен (пространство имен модулей).

Рассмотрим следующий пример, который может помочь прояснить это:

 import datetime class Foo(object): datetime = datetime.datetime >>> datetime <module 'datetime' from '/usr/lib/python2.6/lib-dynload/datetime.so'> >>> Foo.datetime <type 'datetime.datetime'> 

Обратите внимание, что строка datetime = datetime.datetime фактически присваивает имени Foo.datetime , что не является двусмысленным с глобальным datetime (например, если бы тот же самый код был в функции).

Таким образом, поскольку определения классов создают новое пространство имен, а также новую область действия, вам разрешается напрямую обращаться к имени в закрывающей области и назначать одно имя в локальной области.