Свободные переменные рассматриваются как глобальные в 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. В func2
x
является свободной переменной, и согласно утверждению, которое вы нашли, оно рассматривается как глобальное.