Ответ 1
Примечание. exec
- это просто оператор Simple в Python 2.x, тогда как это функция в Python 3.x.
Python 2.7
Давайте проверим изменения, сделанные при выполнении a
.
class Test:
def __init__(self):
l, g = locals().copy(), globals().copy()
exec a # NOT a function call but a statement
print locals() == l, globals() == g
x()
t = Test()
Выход
False True
42
Это означает, что он что-то изменил в словаре locals
. Если вы печатаете locals().keys()
до и после exec
, вы увидите x
, после exec
. Согласно документации exex,
Во всех случаях, если необязательные части опущены, код выполняется в текущей области.
Таким образом, он делает именно то, что говорит документация.
Python 3.x:
Когда мы выполняем то же самое в Python 3.x, мы получаем аналогичный результат, за исключением того, что получаем эту ошибку.
class Test:
def __init__(self):
l, g = locals().copy(), globals().copy()
exec(a) # Function call, NOT a statement
print(locals() == l, globals() == g)
x()
Выход
False True
NameError: name 'x' is not defined
Даже документация функции exec
говорит,
Во всех случаях, если необязательные части опущены, код выполняется в текущей области.
Но он также содержит примечание внизу,
Примечание. Локальные сети по умолчанию действуют, как описано для функции
locals()
ниже: изменения в локальном каталоге по умолчанию не должны выполняться. Передайте явный словарь locals, если вам нужно увидеть эффекты кода на локалях после возврата функцииexec()
.
Итак, мы с любопытством проверяем документацию locals()
и находим
Примечание: Содержимое этого словаря не должно изменяться; изменения могут не влиять на значения локальных и свободных переменных, используемых интерпретатором.
Таким образом, интерпретатор не соблюдает изменения, внесенные в объект locals()
. Вот почему он не распознает x
, как определено в локальной области.
Но когда мы делаем
def __init__(self):
exec(a, globals())
x()
он работает, потому что мы добавляем его в словарь globals
. Сначала Python пытается найти x
в локальной области, а затем в области класса, а затем в глобальной области действия и находит ее там. Поэтому он без проблем запускает его.