Замыкания в Python
Вопрос
Что такое замыкание в Python? Расскажите про nonlocal и про ловушку с лямбдами в цикле.
Попробуйте сами
Ответьте вслух за 2 минуты, как на собесе. Потом сверьтесь с тезисами: что прозвучало, а что нет.
Показать ответ и разбор
Коротко
Что должно прозвучать в ответе
Вложенная функция, которая использует переменные внешней после её завершения
Переменные лежат в ячейках, видно через `__closure__`
Связывается переменная, а не значение: позднее связывание
Для изменения переменной внешней функции нужен `nonlocal`
Применение: фабрики функций, декораторы, счётчики, колбэки
Лечение позднего связывания: аргумент по умолчанию или partial
Что могут спросить следом
- Чем
nonlocalотличается отglobal? - Можно ли заменить замыкание классом и когда это лучше?
- Что выведет
[f() for f in [lambda: i for i in range(3)]]?
Разбор
Образцовый ответ: «Замыкание это вложенная функция, которая использует имена из охватывающей функции и сохраняет к ним доступ после того, как внешняя функция вернула результат. CPython кладёт такие переменные в объекты-ячейки, и у вложенной функции есть __closure__ с этими ячейками. Важно, что сохраняется связь с переменной, а не снимок значения, поэтому если переменная потом изменится, функция увидит новое значение. Отсюда ловушка: список лямбд, созданных в цикле, при вызове вернёт последнее значение счётчика для всех. Лечится аргументом по умолчанию lambda i=i: i или functools.partial. Читать переменную внешней функции можно свободно, а чтобы присвоить ей новое значение, нужно объявить nonlocal, иначе имя станет локальным и будет UnboundLocalError. global в отличие от него ссылается на уровень модуля. На замыканиях построены декораторы, фабрики функций, обработчики с контекстом. Когда состояния много или нужны несколько методов, читабельнее сделать класс».
Ответьте сами, а не прочитайте
В тренажёре вопрос попадёт в повторения и вернётся, когда начнёт забываться. Плюс билеты с зачётом: 20 вопросов, не больше 2 ошибок.
Предыдущий вопрос
Только позиционные и только именованные параметры
Следующий вопрос
Почему опасны изменяемые значения по умолчанию
Термины по теме
Ещё по теме «Функции и области видимости»
- Что такое *args и **kwargs
- Перекрытие встроенных имён
- Как передаются аргументы в функцию Python
- Где хранятся переменные замыкания
- Вызов с *args и **kwargs: разбор сигнатуры
- Композиция функций
- Мемоизация через замыкание
- Повтор вызова с ограничением попыток