Python: Функции
Теория: Отображение (map)
Рассмотрим следующую задачу. Возьмём словарь пользователей и извлечём из него имена всех пользователей:
Здесь мы видим обычную агрегацию с использованием цикла for...in. А что, если нам понадобится извлечь возраст? Повторяем:
В примерах выше легко увидеть закономерность. Выполняется один и тот же проход по циклу, и результат собирается в список result. Единственное, что меняется — значение, которое мы извлекаем из элементов исходного словаря.
Операция, которую мы выполняли в обеих ситуациях, называется отображением (mapping). В коде мы взяли исходную коллекцию и отобразили ее в другую коллекцию, попутно выполнив необходимые преобразования над каждым элементом. Важно, что размер получившейся коллекции равен размеру исходной.
Задача отображать данные в реальном коде встречается буквально на каждом шагу. Это настолько важная операция, что для нее создана специальная функция высшего порядка map():
Функция map() принимает первым параметром функцию, а последующими - коллекции (их может быть несколько). Дальше, внутри себя, map() перебирает элементы переданной коллекции и для каждого элемента вызывает переданную функцию. Возвращает map() уже знакомый вам итератор.
Этот момент очень важен, map() использует ленивые вычисления, и значит функция, переданная в map(), будет применяться к каждому элементу только по запросу.
Вместо перебора в цикле, существует более простой способ извлечь все элементы из итератора - применить конструктор list()
Сравните решение задачи получения списка имен через цикл и с помощью map(). Последний имеет довольно много преимуществ. Во-первых, код с ним значительно короче. Во-вторых, от нас скрыта повторяющаяся логика перебора. Больше не нужно явно определять цикл и выполнять руками все те операции, которые можно не выполнять. Функция map() позволяет сосредоточиться на сути происходящего, скрывая ненужные детали (проход по циклу).
Типичный пример, который любят приводить в документации к функции map() разных языков программирования — применение некоторой арифметической операции к каждому элементу коллекции:
Пример выглядит искусственно, но хорошо отражает суть операции.
Реализация
Напишем свою собственную функцию my_map(), работающую аналогично встроенной функции map():
Главное отличие функции my_map() (и встроенной map()) от ручного обхода коллекции заключается в том, что функция my_map() не знает, что нужно сделать с каждым элементом коллекции. Поэтому она принимает функцию-колбек, которую вызывает для каждого элемента исходной коллекции. Чем будет этот результат — функция my_map() не знает, и ей этого знать не нужно. Ответственность за обработку лежит на пользователях.



