>>> Нелокальное имя
Имя x
, созданное операцией присваивания в начале функции fun
, внутри вложенной функции fun2
экранируется другим именем x
:
>>> def fun():
... x = 'fun'
... def fun2():
... x = 'fun2'
... print(x)
... fun2()
... print(x)
...
>>> fun()
fun2
fun
Чтобы внутри функции fun2
можно было работать с именем x
из пространства имен объемлющей функции, имя x
нужно объявить нелокальным:
>>> x = 'global x'
>>>
>>> def fun():
... x = 'fun'
... def fun2():
... nonlocal x
... x = 'fun2'
... print(x)
... fun2()
... print(x)
...
>>> fun()
fun2
fun2
>>> Имена убивают
Идентификаторы в Python "возникают" и связываются с объектами не только при присваивании, но также при определении функции, класса и в некоторых других случаях. Независимо от способа возникновения, их видимость и доступность подчиняются одним и тем же правилам.
Имя функции fun
внутри функции xyz
экранирует глобальное имя fun
:
>>> def fun():
... print('global fun')
...
>>> def xyz():
... def fun():
... print('inner fun')
... fun()
...
>>> xyz()
inner fun
>>> fun()
global fun
Объявление fun
глобальным внутри функции xyz
позволяет переопределить глобальную функцию fun
:
>>> def fun():
... print('global fun')
...
>>> def xyz():
... global fun
... def fun():
... print('inner fun')
... fun()
...
>>> xyz()
inner fun
>>> fun()
inner fun
>>> Имена называют
Вот полный список случаев, когда в Python создаются идентификаторы и связываются с объектом:
- присваивание,
- предложение
import
, - определение класса,
- определение функции,
- передача аргументов при вызове функции,
- имена в заголовке цикла
for
, - имена в предложении
with
послеas
, - имена в конструкции
except
послеas
.
Несколько примеров:
>>> # math связывается с модулем
... import math
>>> globals()['math']
<module 'math' (built-in)>
>>>
>>> # Cls связывается с классом
>>> class Cls(object):
... pass
...
>>> globals()['Cls']
<class '__main__.Cls'>
>>>
>>> # i связывается с числом
... for i in (0, 1):
... pass
...
>>> globals()['i']
1
>>> Свободные или бесплатные?
Рассмотрим функцию, возвращающую параметризованную функцию. Пусть обе функции выводят на печать свои локальные пространства имен:
>>> def make_add(n):
... print(locals())
... def add(x):
... print(locals())
... return n + x
... return add
...
>>> add2 = make_add(2)
{'n': 2}
>>>
>>> add2(5)
{'x': 5, 'n': 2}
7
В локальном пространстве имен функции add2
имеется имя n
, которое, хотя и было доступно внутри функции add
во время выполнения make_add
, но не определено внутри функции add
непосредственно!
Переменные, используемые внутри функции, но определенные не в ней, а в одном из объемлющих локальных пространств имен, называются бесплатными переменными (free variables) и доступны через локальное пространство имен функции. А функция, использующая бесплатную переменную, называется замыканием (closure).
>>> Разоблачение замыканий
Существование вложенных функций обуславливает существование нелокальных переменых, то есть, переменных определенных в одной из объемлющих функций и доступных внутри вложенной функции.
Существование функций-замыканий есть логическое следствие "первоклассности" функций в Python (functions are first-class citizens). Так как функция, созданная внутри другой функции, может быть возвращена этой другой функцией в качестве результата, то она должна либо потерять связь с нелокальными переменными, либо запомнить, или замкнуть их внутри себя. В результате получается замыкание с бесплатными переменными.
Лямбда-функции так же замыкают нелокальные переменные, как и обычные функции:
>>> def make_add(n):
... add = lambda x: n + x
... return add
...
>>> add3 = make_add(3)
>>> add5 = make_add(5)
>>>
>>> add3(-2)
1
>>> add5(2)
7
Комментариев нет:
Отправить комментарий