список в exec с пустыми локалями: NameError

Рассмотрим следующий фрагмент:

def bar(): return 1 print([bar() for _ in range(5)]) 

Он дает ожидаемый результат [1, 1, 1, 1, 1] .

Однако, если я попытаюсь выполнить один и тот же фрагмент в пустой среде ( locals и globals оба установлены в {} ), он дает NameError :

 if 'bar' in globals() or 'bar' in locals(): del bar # make sure we reset settings exec(""" def bar(): return 1 print([bar() for _ in range(5)]) """, {}, {}) NameError: name 'bar' is not defined 

Если я вызываю exec как exec(…, {}) или exec(…) , он выполняется, как ожидалось.

Зачем?

РЕДАКТИРОВАТЬ:

Рассмотрим также следующий фрагмент:

 def foo(): def bar(): return 1 print('bar' in globals()) # False print('bar' in locals()) # True print(['bar' in locals() for _ in [1]]) # [False] print([bar() for _ in [1, 2]]) # [1, 1] 

Как и в моем первом exec, у нас нет бара у местных жителей в понимании списка. Однако, если мы попытаемся вызвать его, это сработает!

2 Solutions collect form web for “список в exec с пустыми локалями: NameError”

Решение вашей проблемы находится здесь:

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

https://docs.python.org/3/library/functions.html#exec

В основном, ваша проблема заключается в том, что бар определяется в масштабе locals и только у locals . Поэтому этот оператор exec() работает:

 exec(""" def bar(): return 1 print(bar()) """, {}, {}) 

Однако понимание списка создает новую локальную область, в которой bar не определен и поэтому не может быть просмотрен.

Это можно проиллюстрировать следующим образом:

 exec(""" def bar(): return 1 print(bar()) print(locals()) print([locals() for _ in range(1)]) """, {}, {}) 

который возвращается

 1 {'bar': <function bar at 0x108efde18>} [{'_': 0, '.0': <range_iterator object at 0x108fa8780>}] 

РЕДАКТИРОВАТЬ

В вашем исходном примере определение bar находится в глобальной области (уровне модуля). Это соответствует

Помните, что на уровне модуля глобальные и локальные языки являются одним и тем же словарем.

В примере exec вы вводите искусственный раскол в области между глобальными и локальными, передавая два разных словаря. Если вы передали один или два глобала один (что в свою очередь означает, что этот будет использоваться как для globals и для locals ), ваш пример также будет работать.

Что касается примера, введенного в редактировании, это сводится к правилам определения области видимости в python. Для подробного объяснения, пожалуйста, прочтите: https://docs.python.org/3/tutorial/classes.html#python-scopes-and-namespaces

Короче говоря, в то время как bar не находится в локальной области понимания списка и ни в глобальной области, он находится в области foo. И учитывая правила обзора Python, если переменная не найдена в локальной области, она будет искать в охватывающих областях до тех пор, пока не будет достигнута глобальная область видимости. В вашем примере область действия foo находится между локальной областью и глобальной областью, поэтому панель будет найдена до достижения конца поиска.

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

Еще одно замечательное объяснение правил съемки, включая иллюстрации, можно найти здесь: http://sebastianraschka.com/Articles/2014_python_scope_and_namespaces.html

Как выяснил Хендрик Макайт, документация exec говорит, что

Если exec получает два отдельных объекта в качестве globals и locals , код будет выполнен, как если бы он был встроен в определение класса.

Вы можете получить такое же поведение, введя код в определение класса:

 class Foo: def bar(): return 1 print([bar() for _ in range(5)]) 

Запустите его в Python 3, и вы получите

 Traceback (most recent call last): File "foo.py", line 9, in <module> class Foo: File "foo.py", line 15, in Foo print({bar() for _ in range(5)}) File "foo.py", line 15, in <setcomp> print({bar() for _ in range(5)}) NameError: global name 'bar' is not defined 

Причина ошибки заключается в том, что Хендрик сказал, что для понимания списка создается новая неявная локальная область . Однако Python только когда-либо смотрит имена в 2 области: глобальные или локальные. Поскольку ни глобальная, ни новая локальная область не содержат bar имени, вы получаете NameError .

Код работает в Python 2, потому что в представлениях списков есть ошибка в Python 2 в том смысле, что они не создают новую область видимости, и, таким образом, они пропускают переменные в их текущую локальную область:

 class Foo: [1 for a in range(5)] print(locals()['a']) 

Запустите его в Python 2, а выход – 4 . Переменная a теперь находится внутри локалей в классе класса и сохраняет значение из последней итерации. В Python 3 вы получите KeyError .

Вы можете получить ту же ошибку в Python 2, хотя, если вы используете выражение генератора или понимание словаря / набора:

 class Foo: def bar(): return 1 print({bar() for _ in range(5)}) 

Ошибка может быть вызвана просто с помощью просто

 class Foo: bar = 42 class Bar: print(bar) 

Это не похоже на

 def foo(): bar = 42 def baz(): print(bar) baz() 

потому что при выполнении foo Python превращает baz в закрытие, которое будет обращаться к переменной столбца с помощью специальной инструкции байт-кода.

  • Подсчет писем происходит Python
  • Объединение членов класса
  • Модуль python _2or3?
  • Как работает str.startswith?
  • Подключение к серверу Sql с помощью Python 3 в Windows
  • Что такое синтаксис обозначения python .. ("dot dot")?
  • Изменение декоратора кулдауна для работы вместо методов вместо
  • Установка Python 3.4 и 2.7 не содержит папку сценария и не установлена
  • Python - лучший язык программирования в мире.