Формальное определение замыкания
Чтобы в Python возникло замыкание, одновременно должно выполниться три условия:
Внутри одной функции определена другая, вложенная функция.
Внутренняя функция обращается к переменным внешней функции (enclosing scope).
Внешняя функция возвращает внутреннюю функцию, а не результат её вызова.
Получившаяся внутренняя функция «носит с собой» ссылки на переменные внешней функции и может использовать их позже, уже вне исходного контекста.
Простой пример замыкания
def make_adder(x):
def adder(y):
return x + y
return adder
add10 = make_adder(10)
print(add10(5)) # 15
print(add10(7)) # 17Что происходит:
make_adder(10) возвращает функцию adder, которая «помнит», что x = 10.
Переменная x уже не существует как локальная в стеке вызовов make_adder, но значение доступно через замыкание.
Каждый вызов add10(y) использует сохранённое x из enclosing‑области.
Так замыкание позволяет хранить состояние между вызовами функции, не создавая для этого отдельный класс и объект.
Зачем нужны замыкания на практике
Ключевые сценарии, которые часто обсуждают на собеседованиях:
Функции‑фабрики (function factories). Пример выше: make_adder создаёт новые функции с «зашитым» параметром x.
Инкапсуляция состояния. Замыкание может скрывать внутренние данные и предоставлять к ним доступ только через возвращаемые функции — это похоже на приватные поля класса.
Реализация простых стратегий и коллбеков. Функция‑обработчик может помнить параметры окружения, в котором была создана.
Основа для параметризованных декораторов. Декоратор, принимающий аргументы, почти всегда реализуется через замыкание.
Как сформулировать ответ на собеседовании
Замыкание — это вложенная функция, которая запоминает значения из внешней области видимости и может использовать их позже, даже когда внешняя функция уже завершилась. Чтобы возникло замыкание, нужно: внутренняя функция, обращение к переменным внешней и возврат внутренней функции наружу. Это позволяет хранить состояние в функции без отдельного класса.