Формальное определение замыкания
Чтобы в 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 во внешней функции уже не живёт в стеке, но её значение доступно через замыкание.
Каждый вызов add10(y) использует сохранённое x из enclosing‑области.
Так замыкание позволяет хранить состояние между вызовами функции без отдельного класса и объекта.
Где замыкания полезны на практике
Типичные сценарии, про которые часто спрашивают:
Функции‑фабрики (function factories). Как в примере выше: make_adder создаёт новые функции с «зашитым» параметром x.
Инкапсуляция состояния. Замыкание может скрывать внутреннее состояние и давать к нему доступ только через возвращаемые функции — похоже на приватные поля в классах.
Коллбеки и обработчики. Функция‑обработчик может помнить контекст, в котором её создали (настройки, параметры, текущего пользователя).
Параметризованные декораторы. Декоратор с аргументами почти всегда реализуется через замыкание.
Краткая формулировка для собеседования
Замыкание — это вложенная функция, которая запоминает значения из внешней области видимости и может использовать их позже, даже когда внешняя функция уже завершилась. Условия: есть внутренняя функция, она использует переменные внешней и сама функция возвращается наружу. Это способ хранить состояние в функции без класса.