В Python замыкание (closure) — это функция, которая "запоминает" значения внешних переменных, даже если вызывается за пределами их области видимости. Замыкания создаются, когда внутренняя функция ссылается на переменные, определённые во внешней функции. Чтобы изменять такие переменные из вложенной функции в Python 3, используют ключевое слово nonlocal.
Пример:
def make_accumulator(): total = 0 def add(value): nonlocal total total += value return total return add acc = make_accumulator() print(acc(10)) # 10 print(acc(5)) # 15
Без nonlocal переменная total была бы недоступна для изменения (ошибка UnboundLocalError).
Вопрос: "Можно ли внутри вложенной функции увеличить переменную из внешней функции без ключевого слова nonlocal?"
Ответ: Нет, без nonlocal это приведёт к ошибке, так как интерпретатор сочтёт переменную локальной для вложенной функции. Пример:
def outer(): count = 0 def inner(): count += 1 # Ошибка UnboundLocalError return count return inner
История В одном веб-приложении хотели реализовать счётчик локально для каждого обработчика через вложенные функции, однако забыли использовать
nonlocal. Счётчик всегда возвращал 1, так как считал count в локальном пространстве и приращивал новый, не связанный с внешним замыканием.
История В задачах на распараллеливание (multithreading) часто используют замыкания и лямбды. Без понимания замыканий создалась ситуация, когда все лямбда-функции "запоминали" последнее значение переменной цикла, и задания копировали друг друга, вместо обработки разных задач.
История При написании декоратора без использования правильного замыкания (не было передачи параметров во внешний scope) возникла ситуация, в которой декоратор не мог накапливать состояние между вызовами, что привело к неожиданным результатам и нестабильной работе приложения.