globals и locals в python exec ()

Я пытаюсь запустить кусок кода python с помощью exec.

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 

что приводит к следующему результату

  • Область Python
  • UnboundLocalError при манипулировании переменными дает непоследовательное поведение
  • Почему вложенные функции могут обращаться к переменным из внешних функций, но им не разрешено изменять их
  • закрытие python с назначением внешней переменной внутри внутренней функции
  • Области переменных в классах python
  • Использование переменной в try, catch, finally statement без объявления ее вне
  •  locals: {'A': <class 'A'>} A: <class 'A'> Traceback (most recent call last): File "python_test.py", line 16, in <module> exec(my_code_AST, global_env, local_env) File "My Code", line 8, in <module> 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': <class 'A'>} A: <class 'A'> {'A': <class 'A'>, 'B': <class 'B'>} 

    Ясно, что A присутствует и доступно – что происходит в первом фрагменте кода? Я использую 2.6.5, приветствия,

    Colin

    * ОБНОВЛЕНИЕ 1 *

    Если я проверю locals () внутри класса –

     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 () не то же самое в обоих местах –

     locals: {'A': <class 'A'>} A: <class 'A'> {'__module__': '__builtin__'} Traceback (most recent call last): File "python_test.py", line 16, in <module> exec(my_code_AST, global_env, local_env) File "My Code", line 8, in <module> 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

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

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

     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': <class 'A'>} A: <class 'A'> Traceback (most recent call last): File "python_test.py", line 20, in <module> exec(my_code_AST, global_env, local_env) File "My Code", line 11, in <module> File "My Code", line 9, in f NameError: global name 'A' is not defined 

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

  • Ресурсы для лексинга, токенизации и разбора в python
  • Обнаружение мыши на изображении в Pygame
  • Отдел Python
  • Почему 08 или 09 в Python недействительны?
  • Как извлечь аудиофайл из видеофайла с помощью python?
  • Изображение холста tkinter не отображается в классе
  • 4 Solutions collect form web for “globals и locals в python exec ()”

    Ну, я считаю, что это ошибка реализации или недокументированное дизайнерское решение. Суть проблемы в том, что операция привязки имен в области модуля должна связываться с глобальной переменной. То, как это достигается, заключается в том, что когда на уровне модуля 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 

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

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

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

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

    После print locals() и globals() вы найдете причину, по которой exec выдает исключение «не определено», и вы можете попробовать это

     d = dict(locals(), **globals()) exec (code, d, d) 

    Если ваш вопрос заключается в том, как заставить оператор exec вести себя как область файла, я следил за некоторыми подсказками в связанном вопросе и ошибке и заставлял его работать, передавая один словарь для глобальных и локальных пользователей. По-видимому, область файлов – это особый случай, когда локальные объявления автоматически помещаются в глобальную область.

     exec code in dict() 
     my_code = """ class A(object): pass class B(object): a = A """ my_code_AST = compile(my_code, "My Code", "exec") extra_global = "hi" global_env = {} exec my_code_AST in global_env print "global_env.keys() =", global_env.keys() print "Ba =", global_env["B"].a 

    печать

     global_env.keys() = ['__builtins__', 'A', 'B'] Ba = <class 'A'> 

    Хокетт, вы говорите,

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

    С exec, если ваши глобальные значения не определены __builtins__ , exec добавляет один элемент __builtins__ к вашим глобальным значениям, поэтому вы получаете A, B и __builtins__ . Сам __builtins__ – это большой словарь, но всегда один и тот же один элемент для удаления (до тех пор, пока вы дождитесь завершения кода, прежде чем его удалять!). Документировано в разделе exec () здесь .

    Документы для eval по встроенным функциям говорят

    Если словарь глобалов присутствует и отсутствует « встроенные », текущие глобальные переменные копируются в глобалы до того, как выражение будет проанализировано.

    Но на самом деле кажется, что только копия __builtins__ in.

    (И nb, что все остальные сказали: либо установить глобальные и exec my_code_AST in global_env либо сказать exec my_code_AST in global_env без отдельного local_env.)

    Python - лучший язык программирования в мире.