Написать пост

Python map(): все, что вы хотели знать, но боялись спросить не так

Аватарка пользователя Елена Капаца

Разобрали на примерах, как работает Python map(), в чем ее преимущество перед классическими циклами и какие у нее бывают применения-фишки.

Обложка поста Python map(): все, что вы хотели знать, но боялись спросить не так

Когда только-только начинаешь писать код на Python, разобраться, какому объекту уделять больше внимания, непросто. Если вы приступили к программированию и тоже хотите узнать больше про map() — своеобразную звезду языка, эта статья поможет.

Из документации

Мэппинг — это функция, которая применяет другую функцию к итерируемому объекту. Ее цель в том числе — приведение входных данных к нужной форме, чтобы потом их уменьшала reduce().

Python map(): все, что вы хотели знать, но боялись спросить не так 1

Описание функции в документации.

Знающие подметят, что эта пара образует название MapReduce, и да, действительно, эта модель распределенных вычислений для больших объемов данных вовсю использует мэппинг + редукцию.

Рефакторим код с циклом

Представьте, что у нас есть функция my_funс():

			def my_funс(x):
     return х*2
		

Она умножает аргумент на два. А вот наш список ls:

			ls = [1, 2, 3, 4, 5, 6, 7, 8, 9]
		

Вместо классического, но затратного for loop:

			i = 0
while i <= len(ls):
	my_func(ls[i])
	i += 1
		

Можно применить мэппинг, чтобы удвоить все элементы ls один за другим:

			r = map(my_funс, ls) # Заметили, что скобок у my_func нет?
		

Посмотрим, как выглядит r:

			>>> print(r)
...
		

Интерпретатор отдает ссылку на объект в памяти, но r по сути является итератором (то есть вычислений еще не проводилось!). Лишь при преобразовании r в список удвоение запустится:

			>>> list(г)
... [2, 4, 6, 7, 10, 12, 14, 16, 18]
		

Скрытые возможности

Давайте посмотрим, что еще умеет эта замечательная функция. Она действительно способна облегчить нам жизнь в неожиданных ситуациях.

Строки тоже итерируются

map() использует «дочернюю» функцию на любом объекте, где применим цикл for. Мы можем применять ее к любому итерируемому объекту, даже к strings:

			my_string = 'TProger'
		

Импортируем модуль string, чтобы использовать метод capwords() — приведение к верхнему регистру:

			import string
		

Преобразуем все буквы в заглавные:

			>>> list(map(string.capwords, my_string)
... ['T', 'P', 'R', 'O', 'G', 'E', 'R']
		

map() + лямбды

Мы можем комбинировать мэппинг с безымянными функциями, чтобы код стал еще короче:

			list(map(lambda x: x * x, ls))
		

Возведя все элементы списка ls в квадрат, мы получим такой результат:

			[1, 4, 9, 16, 25, 36, 49, 64, 81]
		

self() для обращения объекта к себе

Посмотрите на функцию ниже:

			class Foo():
    
    def __init__(self):
        self.factor = 2
        
    def multiply(self, num):
        return num * self.factor

    def show(self, ls):
        print(list(map(self.multiply, ls)))
		

В данном случае self позволяет перемножить элементы списка на 2:

			>>> f = Foo()
>>> f.show([1,2,3])
... [2, 4, 6]
		

Загонка пользовательского ввода

Сотрудничество map(), input() и list() позволит поместить весь пользовательский текст в список. Это может пригодиться при расчете эмоциональной окраски текста, ведь слова предстоит потом возвращать к исходной форме:

			>>> arr = list(map(str, input().split()))
>>> print(arr)
>>> Это предложение про ввод
... ['Это', 'предложение', 'про', 'ввод']
		

Недостатки map()

Помните ссылку на итератор из первого раздела?

			...
		

К недостаткам map(), так же как и в случае с filter(), можно отнести «ленивую оценку» (Lazy Evaluation). Создатели языка сделали немало в 3-й версии, чтобы улучшить производительность языка, и потому вместо обработанного объекта по умолчанию нам возвращается ссылка на итератор. Пока мы не обернем ее в list() или другой метод, обработка функцией-дочкой еще не произошла.

Это неплохо на малых оборотах, но на практике, где данные весьма разнообразны, без просмотра результата вероятность ошибок на проде увеличивается: мы просто не увидим потенциальных проблем.

Заключение

map() по праву считается воплощением декларативной природы Python. Акцент делается на применении функций, а не на изменении состояния объекта. Функция не манипулирует данными за пределами своей области действия, а лишь создает их видоизмененные экземпляры.

Если вы хотите знать больше не только про map() и reduce(), но еще и про одну участницу трио — filter(), обратитесь к этой статье.
Как часто вы используете map()?
Каждый рабочий день
1-2 раза в месяц
Никогда раньше не использовал(-а)
Следите за новыми постами
Следите за новыми постами по любимым темам
7К открытий14К показов