Python в первую очередь объектно-ориентированный язык. Однако он поддерживает также некоторые возможности функционального программирования, в т.ч. функции высшего порядка, благодаря которым существуют декораторы. Сегодня мы затронем две функции из встроенный библиотеки functools: reduce и partial.
Свертка или редукция reduce из functools
Суть редукции заключается в том, что одна и та же функция последовательно применяется к первому элементу последовательности, затем к полученному результату и второму элементу, затем к полученному результату и третьему элементу и т.д. На самом первого шаге, когда нет предыдущего результата, можно выставить начальное значение.
Например, функция сложения применительно к списку будет выполнять что-то вроде этого:
[1, 2, 3, 4, 5] [3, 3, 4, 5] [6, 4, 5] [10, 5] [15]
Есть разделение на правую и левую редукции. Выше продемонстрирована левая, поскольку выполняется слева направо. Именно левая редукция находится в библиотеке functools под именем reduce
. Функция принимает в качестве параметров: последовательность, применяемую функцию, (опционально) начальное значение.
Вот так можно выстроить вложенные списки (здесь и далее для краткости мы будем обращаться к functools в виде ftl
):
>>> import functools as ftl >>> l = [1, 2, 3, 4, 5] >>> ftl.reduce(lambda x, y: [x, y], l) [[[[1, 2], 3], 4], 5]
Если бы это была правая редукция, то мы бы получили корректный список Лиспа. Или функция умножения применительно к тому же списку с учетом начального значения в виде 10:
>>> ftl.reduce(lambda x, y: x * y, l, 10) 1200
Таким образом, мы получили удесятеренный факториал.
Функция с заданными параметрами через partial из functools
Функция partial
принимает в себя функцию с заданными параметрами и возвращает ее. Возвращенную функцию можно вызвать с параметрами, которые не были заданы.
Например, ниже функция пользовательская foo
имеет 3 параметра. Тогда с помощью partial
мы можем получить такую функцию bar
, которое имеет первым параметром значение, равное 10. А к функции bar
уже задавать свои значения параметров b
и с
.
>>> def foo(a, b, c=3): ... return a + b - c ... >>> bar = ftl.partial(foo, 10) >>> bar(5, 1) # 10 + 5 - 1 14 >>> bar(5) # 10 + 5 - 3 12
Так, например, мы можем задать собственные забавные “прибавлялки” в виде функций, используя более общую функцию сложения. Вот так выглядит функция, которая всегда прибавляет 7 к своим аргументам:
>>> def add(*args): ... return ftl.reduce(lambda x, y: x + y, args) ... >>> add7 = ftl.partial(add, 7) >>> add7(10) 17 >>> add7(10, 20, 30) 67
Мы даже в функции add
использовали знакомую нам редукцию. Хотя могли бы написать что-то вроде такого:
>>> def add(*args): ... res = 0 ... for i in args: ... res += i ... return res
В функциональном стиле это выглядит короче, а вот по производительности не все так однозначно, ведь все-таки итеративный алгоритм в большинстве случаев превосходит рекурсивного и в скорости, и в памяти (поскольку в рекурсии постоянно используется стековый фрейм с возможными оптимизациями для хвостовых рекурсий, если это функциональный язык).
Библиотека functools также предоставляет функцию partialmethod
, которая предназначается для методов класса [1].
Подготовка данных для Data Mining на Python
Код курса
DPREP
Ближайшая дата курса
по запросу
Продолжительность
32 ак.часов
Стоимость обучения
72 000 руб.
Еще больше подробностей о функциональном программировании на Python вы узнаете на наших образовательных курсах в лицензированном учебном центре обучения и повышения квалификации руководителей и IT-специалистов (менеджеров, архитекторов, инженеров, администраторов, Data Scientist’ов и аналитиков Big Data) в Москве:
- DPREP: Подготовка данных для Data Mining на Python
- PYML: Машинное обучение на Python
- Визуализация данных на языке Python
- Computer vision на Python