На этом шаге мы рассмотрим особенности использования внутренних функций.
Вы только что увидели, что функции могут содержать внутренние функции и что даже существует возможность возвращать эти (в других ситуациях скрытые) внутренние функции из родительской функции.
Мы собираемся зайти на территорию функционального программирования еще дальше.
Мало того что функции могут возвращать другие функции, эти внутренние функции также могут захватывать и уносить с собой часть состояния родительской функции. И что же это означает?
Чтобы это проиллюстрировать, мы собираемся немного переписать предыдущий пример функции get_speak_func(). Новая версия сразу принимает аргументы "volume" и "text", чтобы немедленно сделать возвращаемую функцию вызываемой:
def get_speak_func(text, volume): def whisper(): return text.lower() + '...' def yell(): return text.upper() + '!' if volume > 0.5: return yell else: return whisper >>> get_speak_func('Привет, Мир', 0.7)() 'ПРИВЕТ, МИР!'
Теперь взгляните на внутренние функции whisper() и yell(). Обратили внимание на то, что у них больше нет параметра text? Но каким-то непостижимым образом они по-прежнему могут получать доступ к этому параметру text, определенному в родительской функции. На самом деле они, похоже, захватывают и "запоминают" значение этого аргумента.
Функции, которые это делают, называются лексическими замыканиями (lexical closures) (или, для краткости, просто замыканиями). Замыкание помнит значения из своего лексического контекста, даже когда поток управления программы больше не находится в этом контексте.
В практическом плане это означает, что функции могут не только возвращать линии поведения, но и предварительно конфигурировать эти линии поведения. Ниже приведен еще один скелетный пример, который иллюстрирует эту идею:
>>> def make_adder(n): def add(x): return x + n return add >>> plus_3 = make_adder(3) >>> plus_5 = make_adder(5) >>> plus_3(4) 7 >>> plus_5(4) 9
В данном примере make_adder() служит фабрикой для создания и конфигурирования функций-"сумматоров". Обратите внимание на то, что функции-"сумматоры" по-прежнему могут получать доступ к аргументу n функции make_adder() (объемлющему контексту).
На следующем шаге мы рассмотрим функциональное поведение объектов.