Почему определение класса Python не может присвоить себе переменную замыкания? - PullRequest
2 голосов
/ 18 сентября 2009

Почему в Python не работает следующее?

def make_class(a):
    class A(object):
        a=a
    return A

Ответы [ 4 ]

9 голосов
/ 18 сентября 2009

работает просто отлично:

>>> def make_class(a):
    class A(object):
        _a=a
    return A

>>> make_class('df')
<class '__main__.A'>
>>> make_class('df')._a
'df'

Кстати, function не является зарезервированным ключевым словом в Python.

6 голосов
/ 21 сентября 2009

Давайте воспользуемся более простым примером для той же проблемы:

a = 'something'
def boo():
    a = a
boo()

Это невозможно, потому что назначения в python без сопровождающего оператора global или nonlocal означают, что назначенное имя является локальным для текущей области. Это происходит не только в функциях, но и в определениях классов.

Это означает, что вы не можете использовать одно и то же имя для глобальной и локальной переменных и использовать их оба. Вы можете использовать обходной путь из ответа Аарона Дигулии или использовать другое имя:

def make_class(_a):
    class A(object):
        a = _a
    return A
2 голосов
/ 18 сентября 2009

Попробуйте

def make_class(a):
    class A(object): pass
    A.a=a
    return A

Ошибка, которую вы получаете (NameError: name 'a' is not defined), заключается в том, что имя a в классе скрывает параметр a функции; следовательно, a не определено, когда вы пытаетесь "a = a" в вашем коде. Другими словами, правая сторона a является , а не a от def; вместо этого Python ищет его в классе A, поскольку a уже упоминалось в левой части задания.

Это становится более понятным с функциями:

x = 1
def a(x):
    print 'a:',x
    x = 3
    def b():
        print 'b:',x
    b()
a(2)
def c():
    x = x

Очевидно, что первый отпечаток должен печатать 2, а не 1, поэтому параметр x из a должен затенять глобальную переменную x. b определяется в области, где x известен как параметр a, поэтому печать работает.

Однако, если вы попытаетесь вызвать c, вы получите UnboundLocalError: local variable 'x' referenced before assignment, поскольку Python не связывает глобальные переменные автоматически. Чтобы это исправить, вы должны добавить global x перед назначением.

Ваш случай выглядит примерно так:

x = 1
def a(x):
    print 'a:',x
    x = 3
    def b():
        x = x
        print 'b:',x
    b()
a(2)

Хотя печать x работала в приведенном выше примере, назначение не работает. Это мера безопасности, чтобы убедиться, что переменные не просочились. Решение заключается в использовании параметра по умолчанию для «копирования» переменной в область действия b:

x = 1
def a(x):
    print 'a:',x
    x = 3
    def b(x=x):
        x = x
        print 'b:',x
    b()
a(2)

Чтобы решить вашу проблему, вам нужно сказать Python «сделать параметр a из make_class видимым в A», и вам нужно сделать это, прежде чем пытаться присвоить поле a поля учебный класс. Это невозможно в Python. Если бы вы могли сделать a видимым, присваивание изменило бы параметр, а не поле, так как Python не может их различить.

Так как вы не можете сделать его видимым, нет необходимости читать a, следовательно, NameError.

См. здесь для объяснения объема имени в Python.

2 голосов
/ 18 сентября 2009

Оба варианта работают нормально (по крайней мере, в Python 2.5):

>>> def make_class(a):
...     class A(object):
...             _a = a
...     return A
... 
>>> make_class(10)._a
10
>>> def make_class(b):
...     class B(object):
...             def get_b(self):
...                     return b
...     return B
... 
>>> make_class(10)().get_b()
10
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...