Почему я получаю "NameError: имя не определено" с exec()?
Когда я пытаюсь этот код в консоли (в PyCharm):
exec("import random")
exec("def f():\n\treturn random.randint(0, 10), random.randint(0, 10)")
locals()['f']()
это работает отлично. Но когда я пытаюсь сделать то же самое в моей программе, это не работает, и я получаю исключение
NameError: name 'random' is not defined.
Я обнаружил, что этот код не вызывает ошибок:
exec("import random", globals(), globals())
exec("def f():\n\treturn random.randint(0, 10), random.randint(0, 10)", globals(), globals())
globals()['f']()
Но я не могу понять почему.
В чем дело?
1 ответ
Вы не делаете "точно то же самое" в своей программе. Точный код, дословно скопированный в файл и работающий как скрипт Python, работает просто отлично (хотя и без видимого результата).
Я думаю, что вы на самом деле делаете что-то вроде этого:
def import_stuff():
exec("import random")
def do_stuff():
import_stuff()
exec("def f():\n\treturn random.randint(0, 10), random.randint(0, 10)")
locals()['f']()
do_stuff()
Приведенный выше код приводит к NameError
исключение, отмеченное в вашем вопросе, потому что (цитируя документы),
Во всех случаях, если опциональные части опущены, код выполняется в текущей области видимости.
Так как код выше импортирует random
в местном масштабе import_stuff()
, это не видно do_stuff()
,
Фактически, приведенный выше код по своему поведению идентичен следующему:
def import_stuff():
import random
def do_stuff():
import_stuff()
def f():
return random.randint(0, 10), random.randint(0, 10)
f()
do_stuff()
... что тоже не получается по той же причине.
Предполагая, что это действительно происходит в вашем реальном коде, версия изменена, как и в вашем вопросе, добавив globals(), globals()
аргументы exec()
будет работать, потому что тогда вы явно импортируете random
в глобальном масштабе, где все могут видеть это.