Какие библиотеки и паттерны используются для функционального программирования в Python
Что проверяют
Понимаете ли вы функциональный стиль как инструмент, а не как моду: где он делает код на Python проще, а где вредит читаемости. Следом часто просят написать декоратор с кэшем или объяснить, почему lru_cache на методе класса опасен.
Как отвечать
Начните со стандартной библиотеки, её хватает в большинстве задач:
functools:partialдля частичного применения,reduce(из встроенных функций его убрали ещё в Python 3),lru_cacheиcacheдля мемоизации,wrapsдля корректных декораторов,singledispatchдля перегрузки по типу первого аргумента;itertools: ленивые комбинаторыchain,islice,groupby,accumulate,pairwise, а с Python 3.12 ещёbatched;operator:itemgetter,attrgetter,methodcallerвместо однострочныхlambdaвsortedиmap;- сторонние:
toolz(или быстрыйcytoolz) для композиции и каррирования,more-itertoolsдля готовых рецептов,returnsдля контейнеровResultиMaybe,pyrsistentдля персистентных структур.
Из паттернов назовите чистые функции без побочных эффектов, функции высшего порядка и замыкания, декораторы как главный функциональный приём в Python, ленивые вычисления на генераторах и неизменяемость через tuple, frozenset, @dataclass(frozen=True) и NamedTuple. Сопоставление с образцом match (с Python 3.10) тоже часто относят сюда.
Скажите и про границы: оптимизации хвостовой рекурсии в Python нет, лимит рекурсии по умолчанию около тысячи вызовов, а lambda ограничена одним выражением. Поэтому списковое включение обычно читается лучше, чем map с filter и лямбдой внутри.
Где спотыкаются
Вешают @lru_cache на метод экземпляра. Общий для класса кэш держит ссылку на каждый self, и объекты не освобождаются, пока живёт кэш. Для этого есть cached_property или кэш на уровне модуля.
Забывают, что itertools.groupby группирует только соседние элементы. Без предварительной сортировки по тому же ключу группы дробятся.
Путают неизменяемость ссылки и объекта: кортеж со списком внутри остаётся изменяемым по содержимому и не хэшируется, поэтому такой аргумент уронит lru_cache с TypeError.