3.3 Встроенные функции высшего порядка#
В числе встроенных функций также нельзя не отметить функции высшего порядка. Функцией высшего порядка мы будем называть такую функцию, которая в качестве одного из аргументов принимает другую функцию. Во многом это функции, без которых можно и обойтись при решении своих задач, но тем не менее они могут сильно упростить решение. В контексте этого приведем примеры использования двух таких функций в сравнении с кодом, написанным без их использования.
Функция map#
map(func, seq) - применяет функцию func для каждого элемента из последовательности seq
Пример задачи:
Пользователь ввёл ряд чисел с клавиатуры, для дальнейшей работы нужно преобразовать их к правильному типу.
Исходные данные и результат:
numbers = '1, 2, 3, 4, 5' # то, что мы будем использовать как ввод
example_result = [1, 2, 3, 4, 5] # то, что мы ожидаем получить в результате
# Стандартное решение:
split_numbers = numbers.split(', ') # разбиваем строку по разделителю
result_1 = []
for number in split_numbers: # перебираем все элементы и преобразуем их к числу
result_1.append(int(number))
print(result_1)
print(result_1 == example_result) # проверяем, что в процессе получили такой же список чисел
[1, 2, 3, 4, 5]
True
Решение той же задачи с использованием map будет выглядеть следующим образом:
# Решение через map:
split_numbers = numbers.split(', ')
result_generator = map(int, split_numbers) # Для каждого элемента в split_numbers выполняем функцию int
result_2 = list(result_generator) # функция map возвращает объект генератора, чтобы увидеть результат
# преобразуем генератор к списку
print(result_2)
print(result_2 == example_result)
[1, 2, 3, 4, 5]
True
Функция filter#
filter(func, seq) - фильтрует последовательность seq на основе функции func, которая должна возвращать значения True/False
Пример задачи:
Пользователь что-то ввёл с клавиатуры, из введённого текса нужно отобрать только числа.
Исходные данные и результат:
sequence = '1, a, 2, b, c, 3, e, 4, 5' # то, что мы будем использовать как ввод
example_result = ['1', '2', '3', '4', '5'] # то, что мы ожидаем получить в результате
# Стандартное решение:
split_sequence = sequence.split(', ')
result_1 = []
for element in split_sequence: # перебираем все текстовые элементы и проверяем, состоят ли они только из цифр
if element.isdigit():
result_1.append(element)
print(result_1)
print(result_1 == example_result)
['1', '2', '3', '4', '5']
True
Решение той же задачи с использованием filter будет выглядеть следующим образом:
# Решение через filter
split_sequence = sequence.split(', ')
result_generator = filter(str.isdigit, split_sequence)
result_2 = list(result_generator) # функция filter также возвращает объект генератора
print(result_2)
print(result_2 == example_result)
['1', '2', '3', '4', '5']
True
Здесь же отметим ещё две встроенные функции, которые по своей сути не являются функциями высшего порядка, но работают похожим образом - возвращают генераторы и сильно упрощают написание кода
Функция zip#
zip(seq1, seq2, ..., seqn) - принимает на вход любое количество последовательностей и в ответ генерирует кортежи из n’ых элементов. То есть сначала возвращает все первые элементы последовательностей, затем все вторые и так далее. Как только закончится любая из последовательностей, прервется и генератор zip.
Пример задачи:
Есть отдельные списки координат x, y и z, нужно получить список, где каждая координата будет представлена единым кортежем (x, y, z)
Исходные данные и результат:
x = [1, 2, 3, 4, 5]
y = [10, 20, 30, 40, 50, 60]
z = [100, 200, 300, 400, 500, 600, 700]
example_result = [(1, 10, 100), (2, 20, 200), (3, 30, 300), (4, 40, 400), (5, 50, 500)]
# Стандартное решение:
list_length = len(x)
result_1 = []
for i in range(list_length): # Будем перебирать значения индекса в диапазоне длины списка
coordinates = (x[i], y[i], z[i]) # Получаем нужные значения по индексу
result_1.append(coordinates)
print(result_1)
print(result_1 == example_result)
[(1, 10, 100), (2, 20, 200), (3, 30, 300), (4, 40, 400), (5, 50, 500)]
True
Решение той же задачи с использованием zip будет выглядеть следующим образом:
# Решение через zip:
result_generator = zip(x, y, z)
result_2 = list(result_generator)
print(result_2)
print(result_2 == example_result)
[(1, 10, 100), (2, 20, 200), (3, 30, 300), (4, 40, 400), (5, 50, 500)]
True
Функция enumerate#
enumerate(seq) - принимает на вход последовательность и возвращает её элементы с их индексом (последовательным номером). Активно используется в счетных циклах.
Пример задачи:
Вывести порядковые номера для всех элементов последовательности
Исходные данные и результат:
sequence = ['a', 'b', 'c', 'd', 'e']
example_result = [(0, 'a'), (1, 'b'), (2, 'c'), (3, 'd'), (4, 'e')]
# Стандартное решение:
result_1 = []
sequence_length = len(sequence)
for i in range(sequence_length):
result_1.append((i, sequence[i]))
print(result_1)
print(result_1 == example_result)
[(0, 'a'), (1, 'b'), (2, 'c'), (3, 'd'), (4, 'e')]
True
Решение той же задачи с использованием enumerate будет выглядеть следующим образом:
# Решение через enumerate:
result_generator = enumerate(sequence) # в качестве второго аргумента может принимать начало отсчета
result_2 = list(result_generator)
print(result_2)
print(result_2 == example_result)
[(0, 'a'), (1, 'b'), (2, 'c'), (3, 'd'), (4, 'e')]
True
Чаще enumerate будет встречаться в следующем виде:
for i, value in enumerate(sequence):
print(i, value) # Дальше здесь может быть реализована любая логика
0 a
1 b
2 c
3 d
4 e