Веб-версияОткрыть в Telegram

ПостЛовушка замыканий: Почему ваши лямбды в цикле сломаны (Late Binding)

10 сентября 2026
Б
Библиотека Python разработчика | Книги по питону
Ловушка замыканий: Почему ваши лямбды в цикле сломаны (Late Binding) Вы пишете код, который генерирует список функций (например, колбэки для кнопок в UI или динамические фильтры). Кажется, что все логично, но на выходе получаете сюрприз. Проблемный код: # Хотим создать 3 функции, которые возвращают 0, 1 и 2 соответственно funcs = [] for i in range(3): funcs.append(lambda: i) # Проверяем results = [f() for f in funcs] print(results) # Ожидание: [0, 1, 2] # Реальность: [2, 2, 2] Почему так происходит? Это называется Late Binding (позднее связывание). В Python замыкания (closures) захватывают переменные по ссылке, а не по значению. Когда вы объявляете lambda: i, Python не сохраняет текущее число 0, 1 или 2. Он сохраняет инструкцию: «когда меня вызовут, пойди в локальную область видимости, найди переменную с именем i и возьми ее значение». К моменту, когда вы начинаете вызывать функции из списка results, цикл for уже завершился. Переменная i в этой области видимости навсегда осталась равной 2. Все три лямбды смотрят на одну и ту же переменную i. Как лечить? Есть два каноничных способа заставить Python запомнить значение «здесь и сейчас». 1. Аргумент по умолчанию (Hack way) Значения аргументов по умолчанию вычисляются в момент определения функции. funcs = [] for i in range(3): # i=i создает локальную переменную i внутри функции # и присваивает ей текущее значение i из цикла funcs.append(lambda i=i: i) Это работает быстро, но выглядит немного грязно и может сбить с толку линтеры или коллег. 2. functools.partial (Enterprise way) Более чистый и явный способ. partial создает новый callable-объект, «замораживая» переданные аргументы. from functools import partial funcs = [] for i in range(3): # Здесь значение i фиксируется жестко funcs.append(partial(lambda x: x, i)) Где это стреляет в реальной жизни? - Генерация command для кнопок в Tkinter/PyQt. - Динамическое создание task в asyncio циклах. - Патчинг тестов в циклах. Не дайте переменным пережить свое время. #python #internals #functionalprogramming #gotchas 📲 Мы в MAX 👉@BookPython
8 · 1.1K ·

Рядом в ленте

ББиблиотека Python разработчика | Книги по питону📌 Декораторы в Python: как они работают и зачем нужны? Сегодня я покажу вам, как работают декораторы в Python и зачем они вообще нужны. Декораторы позволяют измББиблиотека Python разработчика | Книги по питонуПрофилируем Python в продакшене: почему cProfile не подходит, и чем хорош py-spy Когда на проде начинает течь память или скачет CPU, первая мысль, подключить пр
это сообщение
ББиблиотека Python разработчика | Книги по питону⚡ Как ускорить код на Python? Используем map, filter, reduce ⚡ Привет, друзья! Сегодня расскажу о том, как можно ускорить выполнение кода, заменяя обычные циклыББиблиотека Python разработчика | Книги по питонуProtocol vs ABC: Утиная типизация на стероидах (Static Duck Typing) В классическом ООП (Java, C#) и при использовании abc.ABC в Python мы привыкли к Nominal Sub
ББиблиотека Python разработчика | Книги по питонуБиблиотека Python разработчика | Книги по питону@BookPython · канал · Технологии
18 046подписчиков901средний охват поста
Лента площадки Открыть в Telegram

Открытая публичная лента из поискового индекса ChatCrawler — «Google по публичному Telegram»; обновляется по мере обхода площадки. Время — UTC.

Только публичный контент, официальный API Telegram. О проекте · Вопросы · Чего мы не делаем · Убрать страницу из выдачи · Каталог · Поиск · Как мы считаем