map, filter и reduce
Тема дорожной карты · Python Programming
map, filter и functools.reduce применяют функцию ко всем элементам итерируемого объекта. Однако, в Python, список или генераторное выражение часто оказывается более читаемым: [f(x) for x in xs if pred(x)] предпочтительнее вложенного map(filter(...)). Используйте map или filter, только когда у вас уже есть именованная функция и вам требуется ленивая выдача элементов, так как оба эти метода возвращают итераторы, что позволяет избежать ненужного создания списков. В случае случайного вывода print(map(...)), вы получите объект map, а не значения, так как итераторы не выдают свои значения до тех пор, пока их не пройдет итерация.
reduce намеренно убрали из стандартной библиотеки Python и переместили в модуль functools. Это сделано для того, чтобы пользователи предпочитали более понятные и простые функции, такие как sum, math.prod, any или явные циклы, которые могут быть более очевидны и понятны для других разработчиков.
Как это работает
map, filter и reduce в Python используются для работы с последовательностями данных. Это достигается с помощью модулей map, filter и reduce (из functools), генераторов (yield), итераторов (протокол __iter__/__next__), модуля itertools (включающего функции, такие как chain, groupby, takewhile, product и другие), а также модуля functools (включающего функции, такие как lru_cache, partial, wraps). Декораторы (@decorator) позволяют оборачивать функции дополнительным поведением, сохраняя при этом оригинальное имя и описание функции с помощью @wraps(fn).
Генераторы представляют собой ленивые итераторы, которые выдают по одному элементу за раз. Это делает их идеальными для работы со стримингом или бесконечными последовательностями.
Когда применять
Используйте генераторы, когда источник данных большой или бесконечный (например, логи, сетевой стрим), или когда будет потреблен только префикс последовательности. Генераторы также полезны для композиции трансформаций без промежуточных списков. Функции itertools.chain и groupby могут быть предпочтительнее вложенных циклов, когда они делают намерение более ясным. Функция functools.lru_cache полезна для чистых функций, которые повторно вызываются с теми же аргументами, что позволяет избежать повторной вычислительной работы.
Декораторы идеальны для реализации cross-cutting concerns (логирование, тайминг, retry, auth), так как они позволяют добавлять дополнительное поведение к функциям без необходимости внесения изменений в саму функцию.
Типичные ошибки
Типичные ловушки при использовании map, filter и reduce включают забывание того, что генераторы одноразовые, и что вторая итерация над тем же генератором не вернет никаких значений. Также часто встречается злоупотребление reduce, когда более понятные функции, такие как sum(), min() или max(), были бы более подходящими. Вложенность map(filter(lambda...)) может сделать код менее читаемым по сравнению с использованием генераторных выражений. Декоратор без использования @wraps потеряет информацию об оригинальной функции, что затрудняет отладку и понимание кода. Наконец, использование lru_cache на методе, который использует self, может привести к утечке памяти, так как кеш будет переживать экземпляр класса.
Связанные понятия
- Функциональное программирование и инструменты итерации
- Итераторы и протокол итерации
- Генераторы и yield
- itertools, functools и полезные инструменты
- Python-модули и декораторы
- Python-генераторы и декораторы
- Python-итераторы и декораторы
- Python-функции и декораторы
- Python-декораторы и функции
- Python-генераторы и итераторы