Свободные переменные рассматриваются как глобальные в Python?

В разделе " Модель выполнения" справочного руководства по Python 3.7 я прочел следующее утверждение:

global Оператор имеет ту же область действия, что и операция привязки имени в том же блоке. Если ближайшая область для свободной переменной содержит global Заявление, свободная переменная рассматривается как глобальная.

Поэтому я ввел следующий код в интерпретатор Python:

x =0
def func1():
    global x
    def func2():
        x = 1
    func2()

После звонка func1() Я бы ожидал ценность x в глобальном масштабе, чтобы изменить 1,

Что я не так понял?

1 ответ

Решение

x = 1 в func2 не является свободной переменной. Это просто еще один местный житель; вы привязываетесь к имени и именам, которые по умолчанию являются локальными, если вы не укажете Python иначе.

Из той же модели исполнения документации:

Если имя связано в блоке, оно является локальной переменной этого блока, если не объявлено как nonlocal или же global, [...] Если переменная используется в блоке кода, но не определена там, это свободная переменная.

(Жирный акцент мой)

Вы связали имя в блоке с x = 1, так что это локальная переменная в этом блоке, и не может быть свободной переменной. Таким образом, найденный вами раздел неприменим, потому что это применимо только к свободным переменным:

Если ближайшая область для свободной переменной содержит global Заявление, свободная переменная рассматривается как глобальная.

Вы не должны связывать x в func2()потому что только имена, которые не являются обязательными в области видимости, являются свободными переменными.

Так что это работает:

>>> def func1():
...     global x
...     x = 1
...     def func2():
...         print(x)  # x is a free variable here
...     func2()
...
>>> func1()
1
>>> x
1

x в func2 теперь свободная переменная; это не определено в объеме func2, так что забирает его из родительской области. Родительская область здесь func1, но x помечен глобальным там, так что при чтении x для print() Функция используется глобальное значение.

Сравните это с x не помечен как глобальный в func1:

>>> def func1():
...     x = 1
...     def func2():
...         print(x)  # x is free variable here, now referring to x in func1
...     func2()
...
>>> x = 42
>>> func1()
1

Здесь глобальное имя x установлен в 42, но это не влияет на то, что напечатано. x в func2 свободная переменная, но родительская область func1 только имеет x как местное имя.

Это становится еще интереснее, когда вы добавляете новую внешнюю область видимости, где x все еще местный

>>> def outerfunc():
...     x = 0   # x is a local
...     def func1():
...         global x   # x is global in this scope and onwards
...         def func2():
...             print('func2:', x)  # x is a free variable
...         func2()
...     print('outerfunc:', x)
...     func1()
...
>>> x = 42
>>> outerfunc()
outerfunc: 0
func2: 42
>>> x = 81
>>> outerfunc()
outerfunc: 0
func2: 81

x в outerfunc связано, поэтому не свободная переменная. Поэтому он является локальным в этой области. Однако в func1, global x декларационные знаки x как глобальный во вложенном scrope. В func2x является свободной переменной, и согласно утверждению, которое вы нашли, оно рассматривается как глобальное.

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