Comments 7
Как вы упоминули, автор языка сказал что эти функции оставлены только для обратной совместимости и не надо ими пользоваться: https://mail.python.org/pipermail/python-list/2005-September/342002.html
# ✅ ОТЛИЧНО: Спасибо за нейро-правило "большого пальца"
Так повелось, что для этих функций не завезли нормальной композиции и любая комбинация хотя бы пары подобных операций превращается в callback hell щедро приправленный ключевым словом lambda. Так что соглашусь с первым комментатором, что использовать это не надо. Аккуратнее и проще использовать генераторы и списки сопоставлений нежели вот это вот всё.
Если вам нужна
lambda— пишите генератор
... и тут же список вместо генератора как пример "вот так быстрее". И буквально в следующем примере список "медленнее, потому что вычисляет каждое".
Спасение:
itertools.zip_longest()
Но ведь в zip уже нужное естьzip(..., strict=True)
Привет! Спасибо за внимательность, давай разберем оба пункта.
По первому пункту (про лямбды и генераторы): Признаю, тут у меня вышел косяк с терминологией — под словом «генератор» я имел в виду именно List Comprehension (генератор списка [...]), а не генераторное выражение (...). Согласен, звучит сбивающе с толку, стоит поправить текст, чтобы не путать новичков.
А вот противоречия в скорости там нет, фокус в том, что именно мы передаем в map:
Если это встроенная Си-функция (как
str.lower), тоmapбыстрее генератора списка. Весь цикл прогона крутится на уровне C, интерпретатор не дергает байткод питона на каждой итерации.Но если нужна кастомная
lambda, ситуация меняется.mapвынужден на каждой итерации делать полноценный вызов функции (а в Python вызов функции с созданием фрейма — штука дорогая). Генератор списка (List Comprehension) вычисляет выражение in-place и за счет отсутствия этого оверхеда работает быстрееmap+lambda.
По второму пункту (про zip и strict=True): А вот тут не соглашусь, они решают абсолютно разные задачи. strict=True (я упомянул его в самом конце блока как бонус) — это механизм валидации. Если длины не совпадут, он просто бросит ValueError и положит ваш скрипт. Он не спасет хвост длинного списка от обрезки (fail-fast).
А itertools.zip_longest() нужен именно тогда, когда вам нужно сохранить и обработать данные из длинного списка, заполнив пустоты во втором через fillvalue. То есть одно для строгих контрактов, другое — для сохранения данных.
Разбираем map, filter, reduce, any, all, zip и enumerate в Python