Что такое замыкание?
- Как работают замыкания в Python?
- Зачем нужен nonlocal?
- Почему лямбды в цикле возвращают одно и то же значение?
Замыкание — вложенная функция, которая помнит переменные внешней функции после её завершения.
- Захватывается сама переменная, а не значение на момент создания
- Чтобы присвоить захваченной переменной, нужен
nonlocal
А ещё Ловушка: лямбды в цикле видят последнее значение счётчика
Подробно
Если внутренняя функция использует имя из объемлющей функции, Python сохраняет ссылку на эту переменную в «ячейке» (cell). Внешняя функция может завершиться, а внутренняя продолжит видеть и читать эту переменную. Ячейки видны в func.__closure__.
Зачем: фабрики функций (make_multiplier(3)), декораторы, колбэки с контекстом, простое хранение состояния без класса.
Присваивание. Если внутри вложенной функции присвоить имени значение, Python считает его локальным. Чтобы изменить захваченную переменную, её объявляют nonlocal (для глобальной — global).
Позднее связывание. Замыкание хранит переменную, а не её значение в момент создания. Классическая ловушка — функции, созданные в цикле: все они ссылаются на одну переменную цикла и видят её последнее значение. Решения — аргумент по умолчанию (lambda i=i: i) или functools.partial.
Пример
def counter():
count = 0
def inc():
nonlocal count
count += 1
return count
return inc
c = counter()
c(), c() # (1, 2)
funcs = [lambda: i for i in range(3)]
[f() for f in funcs] # [2, 2, 2] — позднее связывание
funcs = [lambda i=i: i for i in range(3)]
[f() for f in funcs] # [0, 1, 2]Что хотят услышать
- Определение: вложенная функция + захват переменных объемлющей области.
- Где применяется: декораторы, фабрики функций.
nonlocalдля изменения захваченной переменной.- Позднее связывание и способ его обойти.
Частые ошибки
- «Замыкание копирует значение переменной» — хранится ссылка на переменную.
- Получить
UnboundLocalErrorиз-за присваивания безnonlocal.
Проверьте себя
Один верный вариант. Подумайте, потом откройте ответ.
Показать варианты и ответ
- ✗Вложенная функция, которая копирует значения внешних переменных в момент своего создания
- ✗Функция, которая автоматически закрывает файл или соединение после работы
- ✓Вложенная функция, помнящая переменные внешней после её завершения
- ✗Присвоить захваченной переменной во вложенной функции можно без nonlocal
Что спросят дальше
Разбор темы
- Функции — аргументы, области видимости, замыкания и декораторы
Как передаются аргументы, *args и **kwargs, LEGB, ловушка изменяемого значения по умолчанию, замыкания и позднее связывание, декораторы и functools.
Связанные вопросы
Разбор собеседования с sotto
После собеседования sotto разбирает разговор: оценка, каждый вопрос — хорошо, частично или слабо, чего не хватило в ответе и над чем поработать к следующему разу. Первые 30 минут бесплатно.