Свободные переменные рассматриваются как глобальные в Python? - PullRequest
0 голосов
/ 05 октября 2018

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

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

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

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

После вызова func1() я бы ожидал, что значение x в глобальной области видимости изменится на 1.

Что я сделал не так?

1 Ответ

0 голосов
/ 05 октября 2018

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

...