Python Разработка | Web Backend, Парсинг & Telegram Bots. Пайтон программирование с нуля. Django, FastAPI и SQL. Уроки для начинающих и IT карьера. Coding.

@BookPython
Ловушка замыканий: Почему ваши лямбды в цикле сломаны (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 👉 @BookPython
Если у вас установлено приложение,
вы можете сразу перейти в канал