globals и местные жители в должностном лице Python ()

Я пытаюсь выполнить часть кода Python с помощью должностного лица.

my_code = """
class A(object):
  pass

print 'locals: %s' % locals()
print 'A: %s' % A

class B(object):
  a_ref = A
"""

global_env = {}
local_env = {}
my_code_AST = compile(my_code, "My Code", "exec")
exec(my_code_AST, global_env, local_env)

print local_env

который приводит к следующему выводу

locals: {'A': }
A: 
Traceback (most recent call last):
  File "python_test.py", line 16, in 
    exec(my_code_AST, global_env, local_env)
  File "My Code", line 8, in 
  File "My Code", line 9, in B
NameError: name 'A' is not defined

Однако, если я изменяю код на это -

my_code = """
class A(object):
  pass

print 'locals: %s' % locals()
print 'A: %s' % A

class B(A):
  pass
"""

global_env = {}
local_env = {}
my_code_AST = compile(my_code, "My Code", "exec")
exec(my_code_AST, global_env, local_env)

print local_env

затем это хорошо работает - предоставление следующего вывода -

locals: {'A': }
A: 
{'A': , 'B': }

Очевидно A присутствует и доступен - что идет не так, как надо в первой части кода? Я использую 2.6.5, аплодисменты,

Colin

* ОБНОВЛЯЮТ 1 *

Если я проверяю местных жителей () в классе -

my_code = """
class A(object):
  pass

print 'locals: %s' % locals()
print 'A: %s' % A

class B(object):
  print locals()
  a_ref = A
"""

global_env = {}
local_env = {}
my_code_AST = compile(my_code, "My Code", "exec")
exec(my_code_AST, global_env, local_env)

print local_env

Затем становится ясно, что местные жители () не являются тем же в обоих местах -

locals: {'A': }
A: 
{'__module__': '__builtin__'}
Traceback (most recent call last):
  File "python_test.py", line 16, in 
    exec(my_code_AST, global_env, local_env)
  File "My Code", line 8, in 
  File "My Code", line 10, in B
NameError: name 'A' is not defined

Однако, если я делаю это, нет никакой проблемы -

def f():
  class A(object):
    pass

  class B(object):
    a_ref = A

f()

print 'Finished OK'

* ОБНОВЛЯЮТ 2 *

хорошо, таким образом, документы здесь - http://docs.python.org/reference/executionmodel.html

'Определение класса является исполняемым оператором, который может использовать и определить имена. Эти ссылки следуют нормальным правилам для определения имен. Пространство имен определения класса становится словарем атрибута класса. Имена, определенные в объеме класса, не видимы в методах'.

Мне кажется, что должен сделан доступным как свободная переменная в исполняемом операторе, который является определением B, и это происходит, когда мы называем f () выше, но не, когда мы используем должностное лицо (). Это можно более легко показать со следующим -

my_code = """
class A(object):
  pass

print 'locals in body: %s' % locals()
print 'A: %s' % A

def f():
  print 'A in f: %s' % A

f()

class B(object):
  a_ref = A
"""

какие выводы

locals in body: {'A': }
A: 
Traceback (most recent call last):
  File "python_test.py", line 20, in 
    exec(my_code_AST, global_env, local_env)
  File "My Code", line 11, in 
  File "My Code", line 9, in f
NameError: global name 'A' is not defined

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

35
задан hawkett 25 May 2010 в 14:08
поделиться

1 ответ

Что ж, я считаю, что это либо ошибка реализации, либо недокументированное проектное решение. Суть проблемы в том, что операция привязки имени в области модуля должна быть привязана к глобальной переменной. Это достигается тем, что на уровне модуля globals () IS locals () (попробуйте это в интерпретаторе), поэтому, когда вы выполняете любую привязку имени, он, как обычно, назначает его локальным ( ) словарь, который также является глобальным, поэтому создается глобальная переменная.

Когда вы ищете переменную, вы сначала проверяете текущие локальные переменные, и если имя не найдено, вы рекурсивно проверяете локальные переменные, содержащие области видимости, на предмет имени переменной, пока не найдете переменную или не достигнете области видимости модуля. Если вы дойдете до этого, вы проверите глобальные переменные, которые должны быть локальными переменными области видимости модуля.

>>> exec(compile("import sys\nprint sys._getframe().f_code.co_name", "blah", "exec"), {}, {})
<module>
>>> exec("a = 1\nclass A(object):\n\tprint a\n", {}, {})
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<string>", line 2, in <module>
  File "<string>", line 3, in A
NameError: name 'a' is not defined
>>> d = {}
>>> exec("a = 1\nclass A(object):\n\tprint a\n", d,d)
1

Именно из-за такого поведения наследование сработало (при поиске по имени использовалась область видимости объекта кода locals (), в которой действительно был A).

В конце концов, это уродливая уловка в реализации CPython, поиск глобальных переменных в специальном регистре. Это также вызывает некоторые бессмысленные искусственные ситуации - например :

>>> def f():
...     global a
...     a = 1
...
>>> f()
>>> 'a' in locals()
True

Обратите внимание, что это все мои выводы, основанные на вознях с интерпретатором при чтении раздела 4.1 (Именование и привязка) справочника по языку python. Хотя это не окончательно (я не открывал исходные коды CPython), я почти уверен, что прав в отношении поведения.

18
ответ дан 27 November 2019 в 15:45
поделиться
Другие вопросы по тегам:

Похожие вопросы: