Каковы правила области видимости для exec?

У меня есть (как мне кажется) некоторое базовое понимание правил области видимости Python (на основе изучения этот ответ).

Я также узнал из документация на exec, что он принимает globals и locals в качестве необязательных аргументов, и что:

In all cases, if the optional parts are omitted, the code is executed in the current scope.


ПРИМЕЧАНИЕ: все приведенные ниже примеры предполагают использование Python 3.

С учетом сказанного, недавно я наткнулся на этот случай, который меня немного смутил:

def test(passed_data):
    local_result = 5
    exec("print(passed_data)")
    exec("print(local_result)")

    return local_result

print (test('whatever'))

выполнение приведенного выше кода приводит к:

whatever
5
5

Здесь очевидно, что exec имеет доступ к локальным пользователям test (passed_data и local_result).
Хотя, если мы попробуем изменить любой из них:

def test(passed_data):
    local_result = 5
    exec("print(passed_data)")
    exec("print(local_result)")

    exec("passed_data = 222")
    exec("local_result = 111")

    exec("print(passed_data)")
    exec("print(local_result)")

    return local_result

print (test('whatever'))

это приведет к:

whatever
5
whatever
5
5

Использование global внутри exec:

def test(passed_data):
    local_result = 5

    exec("print(local_result)")
    exec("global local_result; local_result = 111")
    exec("print(local_result)")

    return local_result

print (test('whatever'))

дает тот же результат (конечно, поскольку local_result является локальным для test):

5
5
5

Что позволяет нам проверить local_result через exec - это определить его с помощью global:

def test(passed_data):
    global local_result
    local_result = 5

    exec("print(local_result)")
    exec("global local_result; local_result = 111")
    exec("print(local_result)")

    return local_result

print (test('whatever'))

Это дает нам:

5
111
111

Мне кажется, что мне просто не хватает базового понимания области видимости Python или механики exec, чтобы разобраться в этом случае.
Тем не менее, я хотел бы понять следующее:

  1. Почему exec может печатать переменную из области действия функции без использования global, но не может ее изменить?
  2. Насколько я понимаю, (данные globals и locals опущены) exec будет выполнять любой код Python в той области, из которой он вызывается, как если бы этот код был только в источнике (без exec), где (и как) я ошибаюсь в этом предположении?

P.S .: Я понимаю, что изменение локальной переменной через exec - это «неправильный поступок», я ищу понимание правил области видимости exec просто ради обучения.

Локальные переменные подлежат оптимизации, которая предотвращает их динамическое изменение. Аналогичным примером является примечание в docs.python.org/3/library/functions.html#locals. Глобальные переменные не имеют этих ограничений, но для того, чтобы компилятор распознал переменную как глобальную, а не как локальную, требуется оператор global вне exec.

Alex Hall 10.03.2018 09:33

Оформить заказ на этот ответ Я только что отправил stackoverflow.com/a/49208472/2867928

kasravnd 10.03.2018 12:22

@AlexHall, спасибо, что указали на соответствующий раздел документации!

user8554766 13.03.2018 11:23

@Kasramvd, я проверил ваш ответ - он действительно объясняет то же самое. Спасибо!

user8554766 13.03.2018 11:24
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
4
30
0

Другие вопросы по теме