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

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

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 было по существу областью:

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

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

Ответ 1

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

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

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

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

Ответ 2

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

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 (например, было бы, если бы тот же код был в функции).

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