Функции высшего порядка: map, filter, reduce, partial

⏱ 25 мин · 🧩 заданий: 5

Функции высшего порядка

Функция высшего порядка принимает функцию как аргумент или возвращает функцию. Вы уже встречали их: sorted(key=...), max(key=...), фабрики-замыкания.

def apply(func, values):
    return [func(v) for v in values]

print(apply(abs, [-1, 2, -3]))
print(apply(str.upper, ["a", "b"]))
print(apply(lambda x: x ** 3, [1, 2, 3]))

map

map(func, iterable, ...) применяет функцию к каждому элементу. Возвращает ленивый итератор:

nums = ["1", "2", "3"]
m = map(int, nums)
print(m)                     # ещё ничего не вычислено
print(list(m))               # вычисление при переборе
print(list(m))               # итератор одноразовый

print(list(map(pow, [2, 3, 4], [10, 2, 1])))   # несколько итерируемых — несколько аргументов
print(sum(map(int, "12345")))                    # сумма цифр числа

filter

filter(func, iterable) оставляет элементы, для которых функция истинна. С None вместо функции — убирает ложные значения:

nums = [0, 5, -3, 8, 0, 2]
print(list(filter(lambda x: x > 0, nums)))
print(list(filter(None, ["a", "", None, "b", 0])))
print(list(filter(str.isdigit, ["12", "ab", "3"])))

map/filter или включение?

nums = range(10)
a = list(map(lambda x: x * 2, filter(lambda x: x % 3 == 0, nums)))
b = [x * 2 for x in nums if x % 3 == 0]
print(a == b, b)

В Python чаще пишут включения — они читаются легче. map удобен, когда функция уже есть: map(int, items), map(str.strip, lines).

reduce

functools.reduce(func, iterable, initial) сворачивает последовательность в одно значение, применяя функцию попарно слева направо:

from functools import reduce

print(reduce(lambda acc, x: acc + x, [1, 2, 3, 4]))        # ((1+2)+3)+4
print(reduce(lambda acc, x: acc * x, [1, 2, 3, 4], 1))
print(reduce(max, [3, 9, 2]))
print(reduce(lambda acc, w: acc + len(w), ["кот", "собака"], 0))
reduce(f, [a, b, c, d], init) = f(f(f(f(init, a), b), c), d)

Для частых случаев есть встроенные функции — используйте их: sum, max, min, math.prod, "".join, any, all.

any и all

ages = [25, 17, 34]
print(any(a < 18 for a in ages))      # есть хотя бы один несовершеннолетний
print(all(a >= 18 for a in ages))     # все взрослые
print(any([]), all([]))               # False True — для пустых

Обе функции ленивые: any останавливается на первом истинном, all — на первом ложном.

partial

functools.partial фиксирует часть аргументов функции:

from functools import partial

def power(base, exp):
    return base ** exp

square = partial(power, exp=2)
two_to = partial(power, 2)
print(square(7), two_to(10))

log_error = partial(print, "[ERROR]", sep=" | ")
log_error("диск заполнен", "код 28")

Модуль operator

Готовые функции для операторов — короче lambda и чуть быстрее:

import operator
from functools import reduce

print(reduce(operator.mul, [1, 2, 3, 4]))
print(list(map(operator.add, [1, 2], [10, 20])))
get_name = operator.itemgetter("name")
print(get_name({"name": "Анна", "age": 30}))
print(operator.attrgetter("real")(3 + 4j), operator.methodcaller("upper")("abc"))

Композиция функций

def compose(f, g):
    return lambda x: f(g(x))

strip_upper = compose(str.upper, str.strip)
print(strip_upper("   привет  "))

pipeline = [str.strip, str.lower, lambda s: s.replace(" ", "-")]
text = "  Заголовок Статьи  "
for step in pipeline:
    text = step(text)
print(text)

Итог

  • Функции — объекты первого класса: их передают и возвращают.
  • map и filter возвращают ленивые одноразовые итераторы; в коде чаще используют включения.
  • reduce сворачивает последовательность; для типичных случаев есть sum, max, math.prod.
  • any/all — ленивые проверки; partial фиксирует аргументы; operator — функции-операторы.

Практика решено 0 из 5

Вы не вошли — ответы проверяются, но прогресс не сохранится. Войти или зарегистрироваться.
Задание 1 Программа на Python

С помощью map и filter (без списковых включений) получите список result: квадраты нечётных чисел из nums.

Какие тесты проверяют код (1)
assert result == [1, 9, 25, 49]
Задание 2 Программа на Python

С помощью functools.reduce напишите функцию product(nums) — произведение всех чисел списка. Для пустого списка верните 1.

Какие тесты проверяют код (3)
assert product([1, 2, 3, 4]) == 24
assert product([]) == 1
assert product([5]) == 5
Задание 3 Программа на Python

Напишите функцию compose(*funcs), которая возвращает композицию функций, применяемых справа налево: compose(f, g, h)(x) == f(g(h(x))). Без функций — тождественная функция.

Какие тесты проверяют код (3)
inc = lambda x: x + 1; dbl = lambda x: x * 2; assert compose(inc, dbl)(5) == 11
assert compose(str, abs)(-3) == "3"
assert compose()(42) == 42
Задание 4 Один вариант ответа

Что выведет код?

m = map(str.upper, ["a", "b"])
print(list(m))
print(list(m))
Задание 5 Программа на Python

С помощью functools.partial создайте функцию to_int_base2, которая переводит строку из двоичной системы в число (на основе встроенной int(x, base)).

Какие тесты проверяют код (2)
assert to_int_base2("1010") == 10
assert to_int_base2("11111111") == 255

Войдите, чтобы отмечать пройденные уроки.