1 ноября 2012 г.

Python, области видимости


Области видимости и
вложенные функции

С появлением вложенных функций в области видимости поиск стал сложнее.

Внутри функции:
  • При обращении к переменной (X) поиск имени X сначала производится в локальной области видимости (функции)затем в локальных областях видимости всех
лексически-объемлющих функций, изнутри наружу, затем в текущей глобальной области видимости (в модуле) и, наконец, во встроенной области видимости (модуль builtins). Поиск имен, объявленных в инструкции global, начинается сразу с глобальной (в модуле) области видимости.

  • Операция присваивания (X = value) по умолчанию создает или изменяет имя
X в текущей локальной области видимости. Если имя X объявлено глобальным внутри функции, операция присваивания создает или изменяет имя X в области видимости объемлющего модуля. Если имя X объявлено нелокальным внутри функции, операция присваивания создает или изменяет имя X в ближайшей области видимости объемлющей функции.

Обратите  внимание,  что  инструкция  global  отображает  имена  в  область видимости объемлющего  модуля.  Когда  имеются вложенные функции,  можно получить значения переменных в объемлющих функциях, но чтобы их изменить, переменные должны быть указаны в объявлении nonlocal.

Примеры вложенных областей видимости:
X = 99    # Имя в глобальной области видимости: не используется

def f1():
    X = 88             # Локальное имя в объемлющей функции
    def f2():
        print(X)# Обращение к переменной во вложенной функции
    f2()

f1() # Выведет 88: локальная переменная в объемлющей функции

Объемлющая функция - функция которая содержит в себе вложенную функцию.
-----------------------------------------------------------------

def f1():
    X = 88
    def f2():
        print(X)   # Сохраняет значение X в объемлющей области видимости
    return f2      # Возвращает f2, но не вызывает ее

action = f1()      # Создает и возвращает функцию
action()           # Вызов этой функции: выведет 88

Функция которая создает и возвращает другую функцию. При вызове action фактически запускается функция, созданная во время выполнения функции f1. Функция f2 помнит переменную X в области видимости объемлющей функции f1, которая уже неактивна.
-----------------------------------------------------------------

Фабричные функции(замыкание):
Подразумевается объект функции, который сохраняет  значения  в  объемлющих  областях
видимости,  даже  когда  эти  области могут  прекратить  свое существование. Классы более подходящий объект, который сохраняет состояние, путем присваивания атрибуту значения.

Используются фабричные функции, когда необходимо создать обработчик событий в процессе выполнения.
>>> def maker(N):
...     def action(X):     # Создать и вернуть функцию
...        return X ** N   # Функция action запоминает значение N в объемлющей
...    return action       # области видимости
...
Здесь определяется внешняя  функция, которая просто  создает  и возвращает
вложенную функцию, не вызывая ее. Если вызвать внешнюю функцию:
>>> f = maker(2)                # Запишет 2 в N
>>> f
<function action at 0x014720B0>
она вернет ссылку на созданную ею вложенную функцию, созданную при выполнении вложенной инструкции def. Если теперь вызвать то, что было получено от внешней функции:
>>> f(3)       # Запишет 3 в X, в N по-прежнему хранится число 2
9
>>> f(4)       # 4 ** 2
16 

Если снова вызвать внешнюю функцию, мы получим новую вложенную
функцию уже  с  другой  информацией о состоянии.

>>> g = maker(3)       # Функция g хранит число 3, а f – число 2
>>> g(3)               # 3 ** 3
27
>>> f(3)               # 3 ** 2
9

В результате вместо квадрата будет вычисляться куб аргумента, но ранее сохраненная функция по-прежнему будет возвращать квадрат аргумента.

Вообще классы, которые будут обсуждаться позднее, лучше подходят на роль «памяти», как в данном случае, потому что они обеспечивают явное сохранение информации.

1 комментарий: