Python's map(): Обработка итераций без цикла
Оглавление
- Написание кода в функциональном стиле на Python
- Начало работы с Python'ом map()
- Преобразование повторяющихся значений строк с помощью Python's map()
- Преобразование повторяющихся чисел с помощью Python's map()
- Объединение map() С Другими Функциональными Инструментами
- Обработка итераций на основе кортежей с помощью звездной карты()
- Кодирование в стиле Python: замена map()
- Заключение
Смотрите сейчас, к этому уроку прилагается соответствующий видеокурс, созданный командой Real Python. Посмотрите его вместе с письменным руководством, чтобы углубить свое понимание: Функция map() в Python: преобразование повторяемых объектов
В Python map() есть встроенная функция, которая позволяет обрабатывать и преобразовывать все элементы в виде итерации без использования явного цикла for, этот метод, широко известный как отображение. map(), полезен когда вам нужно применить функцию преобразования к каждому элементу в iterable и преобразовать их в новый iterable. map() это один из инструментов, поддерживающих функциональное программирование стиль в Python.
В этом уроке вы узнаете:
- Как работает Python
map() - Как преобразовать различные типы итераций Python с помощью
map() - Как комбинировать
map()с другими функциональными инструментами для выполнения более сложных преобразований - Какие инструменты вы можете использовать, чтобы заменить
map()и сделать ваш код более питоническим
Обладая этими знаниями, вы сможете эффективно использовать map() в своих программах или, в качестве альтернативы, использовать представления списков или генераторных выражений чтобы сделать ваш код более понятным на языке Python.
Для лучшего понимания map() необходимы некоторые предварительные знания о том, как работать с итерируемыми, for циклами, функциями и lambda функции были бы полезны.
Бесплатный бонус: 5 Размышления о мастерстве владения Python, бесплатный курс для разработчиков Python, который показывает вам план действий и мышление, с которым вы будете работать. вам нужно поднять свои навыки работы с Python на новый уровень.
Кодирование в функциональном стиле на Python
В функциональном программировании, вычисления выполняются путем объединения функций, которые принимают аргументы и возвращают в результате конкретное значение (или величины). Эти функции не изменяют свои входные аргументы и не изменяют состояние программы. Они просто предоставляют результат заданного вычисления. Такие функции обычно известны как чистые функции.
Теоретически, программам, построенным с использованием функционального стиля, будет проще:
- Разрабатывайте, потому что вы можете кодировать и использовать каждую функцию изолированно
- Отладка и тестирование потому что вы можете тестировать и отлаживать отдельные функции не заглядывая в остальную часть программы
- Поймите, потому что вам не нужно иметь дело с изменениями состояния на протяжении всей программы
В функциональном программировании обычно используются списки, массивы и другие повторяющиеся объекты для представления данных, а также набор функций, которые работают с этими данными и преобразуют их. Когда дело доходит до обработки данных в функциональном стиле, существует, по крайней мере, три наиболее часто используемых метода:
-
Отображение состоит в применении функции преобразования к итерируемой переменной для создания новой итерируемой переменной. Элементы в новой итерационной таблице создаются путем вызова функции преобразования для каждого элемента в исходной итерационной таблице.
-
Фильтрация заключается в применении предиката или логически значимой функции к итерируемому объекту для создания нового итерируемого объекта. Элементы в новой iterable создаются путем фильтрации любых элементов в исходной iterable, из-за которых функция предиката возвращает значение false.
-
Сокращение заключается в применении функции сокращения к повторяющейся переменной для получения единого суммарного значения.
Согласно Гвидо ван Россуму, на Python более сильное влияние оказывают императивные языки программирования, чем функциональные языки:
Я никогда не считал, что на Python сильно влияют функциональные языки, независимо от того, что говорят или думают люди. Я был гораздо лучше знаком с императивными языками, такими как C и Algol 68, и, хотя я делал функции первоклассными объектами, я не рассматривал Python как функциональный язык программирования. (Источник)
Однако еще в 1993 году сообщество разработчиков Python требовало некоторых функциональных возможностей программирования. Они просили:
- Анонимные функции
- A
map()функция - A
filter()функция - A
reduce()функция
Эти функциональные возможности были добавлены в язык благодаря вкладу члена сообщества. В настоящее время, map(), filter(), и reduce() являются фундаментальными компонентами функционального стиля программирования на Python.
В этом руководстве вы познакомитесь с одной из таких функциональных возможностей - встроенной функцией map(). Вы также узнаете, как использовать описания списков и генераторные выражения, чтобы получить ту же функциональность, что и map(), на языке Python и в удобочитаемом виде.
Начало работы с Python map()
Иногда вы можете столкнуться с ситуациями, в которых вам нужно выполнить одну и ту же операцию со всеми элементами входного итерируемого объекта, чтобы создать новый итерируемый объект. Самый быстрый и распространенный подход к решению этой проблемы - использовать цикл Python for. Однако вы также можете решить эту проблему без явного цикла, используя map().
В следующих трех разделах вы узнаете, как работает map() и как вы можете использовать его для обработки и преобразования повторяющихся значений без цикла.
Понимание map()
map() выполняет циклический переход по элементам входного iterable (или iterables) и возвращает итератор, который является результатом применения функции преобразования к каждому элементу исходного входного iterable.
В соответствии с документацией , map() принимает функциональный объект и итерацию (или несколько итераций) в качестве аргументов и возвращает итератор, который выдает преобразованные элементы по требованию. Сигнатура функции определяется следующим образом:
map(function, iterable[, iterable1, iterable2,..., iterableN])
map() применяет function к каждому элементу в iterable в цикле и возвращает новый итератор, который выдает преобразованные элементы по требованию. function может быть любой функцией Python для этого требуется количество аргументов, равное количеству итераций, которые вы передаете map().
Примечание: Первым аргументом map() является объект функции, что означает, что вам нужно передать функцию, не вызывая ее. То есть без использования пары круглых скобок.
Этот первый аргумент map() является функцией преобразования . Другими словами, это функция, которая преобразует каждый исходный элемент в новый (преобразованный) элемент. Несмотря на то, что в документации Python этот аргумент называется function, он может быть любым вызываемым на Python. Сюда входят встроенных функций, классы, методы, lambda функций и пользовательских функций.
Операция, которую выполняет map(), обычно называется отображением, поскольку она сопоставляет каждый элемент во входной итеративной переменной с новым элементом в результирующей итеративной таблице. Чтобы сделать это, map() применяет функцию преобразования ко всем элементам входного итеративного параметра.
Чтобы лучше понять map(), предположим, вам нужно взять список числовых значений и преобразовать его в список, содержащий квадратичное значение каждого числа из исходного списка. В этом случае вы можете использовать цикл for и закодировать что-то вроде этого:
>>> numbers = [1, 2, 3, 4, 5]
>>> squared = []
>>> for num in numbers:
... squared.append(num ** 2)
...
>>> squared
[1, 4, 9, 16, 25]
Когда вы запускаете этот цикл на numbers, вы получаете список квадратных значений. Цикл for повторяется на numbers и применяет операцию преобразования к каждому значению. Наконец, он сохраняет результирующие значения в squared.
Вы можете добиться того же результата без использования явного цикла, используя map(). Взгляните на следующую повторную реализацию приведенного выше примера:
>>> def square(number):
... return number ** 2
...
>>> numbers = [1, 2, 3, 4, 5]
>>> squared = map(square, numbers)
>>> list(squared)
[1, 4, 9, 16, 25]
square() это функция преобразования, которая преобразует число в его квадратное значение. Вызов map() применяет square() ко всем значениям в numbers и возвращает итератор, который выдает квадратные значения. Затем вы вызываете list() на map(), чтобы создать объект списка, содержащий квадратные значения.
Поскольку map() написан на C и сильно оптимизирован, его внутренний подразумеваемый цикл может быть более эффективным, чем обычный цикл Python for. Это одно из преимуществ использования map().
Второе преимущество использования map() связано с потреблением памяти. При использовании цикла for вам необходимо сохранить весь список в памяти вашей системы. С помощью map() вы получаете товары по запросу, и только один элемент находится в памяти вашей системы в данный момент времени.
Примечание: В Python 2.x, map() возвращает список. Это поведение изменилось в Python 3.x. Теперь map() возвращает объект map, который является итератором, выдающим элементы по запросу. Вот почему вам нужно вызвать list(), чтобы создать нужный объект списка.
В качестве другого примера, допустим, вам нужно преобразовать все элементы в списке из строки в целое число. Для этого вы можете использовать map() вместе с int() следующим образом:
>>> str_nums = ["4", "8", "6", "5", "3", "2", "8", "9", "2", "5"]
>>> int_nums = map(int, str_nums)
>>> int_nums
<map object at 0x7fb2c7e34c70>
>>> list(int_nums)
[4, 8, 6, 5, 3, 2, 8, 9, 2, 5]
>>> str_nums
["4", "8", "6", "5", "3", "2", "8", "9", "2", "5"]
map() применяется int() к каждому значению в str_nums. Поскольку map() возвращает итератор (объект карты), вам потребуется вызвать list(), чтобы вы могли завершить итератор и превратить его в объект списка. Обратите внимание, что исходная последовательность не изменяется в процессе.
Использование map() С различными видами функций
Вы можете использовать любой вызываемый объект Python с помощью map(). Единственным условием будет то, что вызываемый объект принимает аргумент и возвращает конкретное и полезное значение. Например, вы можете использовать классы, экземпляры, которые реализуют специальный метод, называемый __call__(), методы экземпляра, методы класса, статические методы и функции.
Существует несколько встроенных функций, которые можно использовать с map(). Рассмотрим следующие примеры:
>>> numbers = [-2, -1, 0, 1, 2]
>>> abs_values = list(map(abs, numbers))
>>> abs_values
[2, 1, 0, 1, 2]
>>> list(map(float, numbers))
[-2.0, -1.0, 0.0, 1.0, 2.0]
>>> words = ["Welcome", "to", "Real", "Python"]
>>> list(map(len, words))
[7, 2, 4, 6]
Вы можете использовать любую встроенную функцию с map(), при условии, что функция принимает аргумент и возвращает значение.
Общий шаблон, который вы увидите, когда дело дойдет до использования map(), заключается в использовании функции lambda в качестве первого аргумента. lambda функции удобны, когда вам нужно передать выражение-функция, основанная на map(). Например, вы можете переопределить пример квадратных значений, используя функцию lambda следующим образом:
>>> numbers = [1, 2, 3, 4, 5]
>>> squared = map(lambda num: num ** 2, numbers)
>>> list(squared)
[1, 4, 9, 16, 25]
lambda функции весьма полезны, когда дело доходит до использования map(). Они могут играть роль первого аргумента для map(). Вы можете использовать функции lambda вместе с функциями map() для быстрой обработки и преобразования ваших итераций.
Обработка нескольких входных Итераций С помощью map()
Если вы задаете несколько итераций в map(), то функция преобразования должна принимать столько аргументов, сколько итераций вы передаете. Каждая итерация map() будет передавать одно значение из каждой итерационной таблицы в качестве аргумента в function. Итерация останавливается в конце самой короткой итерационной таблицы.
Рассмотрим следующий пример, в котором используется pow():
>>> first_it = [1, 2, 3]
>>> second_it = [4, 5, 6, 7]
>>> list(map(pow, first_it, second_it))
[1, 32, 729]
pow() принимает два аргумента, x и y, и возвращает значение x в степени y. На первой итерации x будет 1, y будет 4, а результатом будет 1. На второй итерации x будет 2, y будет 5, а результатом будет 32 и так далее. Конечная итерируемая величина имеет длину, равную длине самой короткой итерируемой величины, которая в данном случае равна first_it.
Этот метод позволяет объединить две или более итерационных таблицы числовых значений, используя различные виды математических операций. Вот несколько примеров, в которых используются функции lambda для выполнения различных математических операций с несколькими входными итерационными таблицами:
>>> list(map(lambda x, y: x - y, [2, 4, 6], [1, 3, 5]))
[1, 1, 1]
>>> list(map(lambda x, y, z: x + y + z, [2, 4], [1, 3], [7, 8]))
[10, 15]
В первом примере вы используете операцию вычитания для объединения двух повторяющихся значений по три элемента в каждом. Во втором примере вы складываете значения трех повторяющихся значений.
Преобразование повторяющихся строк с помощью Python map()
Когда вы работаете с повторяемыми строковыми объектами, вам может быть интересно преобразовать все объекты с помощью какой-либо функции преобразования. map() из Python может стать вашим союзником в таких ситуациях. В следующих разделах вы познакомитесь с некоторыми примерами использования map() для преобразования повторяющихся объектов string.
Используя методы str
Довольно распространенным подходом к манипулированию строками является использование некоторых из методов класса str чтобы преобразуйте заданную строку в новую. Если вы имеете дело с повторяющимися строками и вам нужно применить одно и то же преобразование к каждой строке, то вы можете использовать map() наряду с различными строковыми методами:
>>> string_it = ["processing", "strings", "with", "map"]
>>> list(map(str.capitalize, string_it))
['Processing', 'Strings', 'With', 'Map']
>>> list(map(str.upper, string_it))
['PROCESSING', 'STRINGS', 'WITH', 'MAP']
>>> list(map(str.lower, string_it))
['processing', 'strings', 'with', 'map']
Существует несколько преобразований, которые вы можете выполнить с каждым элементом в string_it, используя map() и строковые методы. В большинстве случаев вы бы использовали методы, которые не принимают дополнительных аргументов, например str.capitalize(), str.lower(), str.swapcase(), str.title(), и str.upper().
Вы также можете использовать некоторые методы, которые принимают дополнительные аргументы со значениями по умолчанию, например str.strip(), который принимает необязательный аргумент с именем char, который используется по умолчанию для удаления пробелов:
>>> with_spaces = ["processing ", " strings", "with ", " map "]
>>> list(map(str.strip, with_spaces))
['processing', 'strings', 'with', 'map']
Когда вы используете str.strip() таким образом, вы полагаетесь на значение по умолчанию char. В этом случае вы используете map(), чтобы удалить все пробелы в элементах with_spaces.
Примечание: Если вам нужно указать аргументы, а не полагаться на значение по умолчанию, вы можете использовать функцию lambda.
Вот пример, в котором используется str.strip() для удаления точек вместо пробелов по умолчанию:
>>> with_dots = ["processing..", "...strings", "with....", "..map.."]
>>> list(map(lambda s: s.strip("."), with_dots))
['processing', 'strings', 'with', 'map']
Функция lambda вызывает .strip() для объекта string s и удаляет все начальные и конечные точки.
Этот метод может быть полезен, например, при обработке текстовых файлов, в строках которых могут быть пробелы в конце (или другие символы), и их необходимо удалить. Если это так, то вам нужно учитывать, что использование str.strip() без пользовательского char также приведет к удалению символа новой строки.
Удаление знаков препинания
Когда дело доходит до обработки текста, иногда возникает необходимость удалить знаки препинания, которые остаются после разбиения текста на слова. Чтобы решить эту проблему, вы можете создать пользовательскую функцию, которая удаляет знаки препинания из одного слова, используя регулярное выражение, соответствующее наиболее распространенным знакам препинания.
Вот возможная реализация этой функции с использованием sub(), , которая является функцией регулярного выражения, которая находится в модуле re в стандартной библиотеке Python:
>>> import re
>>> def remove_punctuation(word):
... return re.sub(r'[!?.:;,"()-]', "", word)
>>> remove_punctuation("...Python!")
'Python'
Внутри remove_punctuation() вы используете шаблон регулярного выражения, который соответствует наиболее распространенным знакам препинания, которые вы найдете в любом тексте, написанном на английском языке. Вызов re.sub() заменяет совпадающие знаки препинания пустой строкой ("") и возвращает очищенный word.
При наличии функции преобразования вы можете использовать map() для выполнения преобразования каждого слова в вашем тексте. Вот как это работает:
>>> text = """Some people, when confronted with a problem, think
... "I know, I'll use regular expressions."
... Now they have two problems. Jamie Zawinski"""
>>> words = text.split()
>>> words
['Some', 'people,', 'when', 'confronted', 'with', 'a', 'problem,', 'think'
, '"I', 'know,', "I'll", 'use', 'regular', 'expressions."', 'Now', 'they',
'have', 'two', 'problems.', 'Jamie', 'Zawinski']
>>> list(map(remove_punctuation, words))
['Some', 'people', 'when', 'confronted', 'with', 'a', 'problem', 'think',
'I', 'know', "I'll", 'use', 'regular', 'expressions', 'Now', 'they', 'have
', 'two', 'problems', 'Jamie', 'Zawinski']
В этом фрагменте текста некоторые слова содержат знаки препинания. Например, у вас есть 'people,' вместо 'people', 'problem,' вместо 'problem' и так далее. Вызов map() применяется remove_punctuation() к каждому слову и удаляет все знаки препинания. Итак, во втором list вы вычистили слова.
Обратите внимание, что апостроф (') отсутствует в вашем регулярном выражении, потому что вы хотите сохранить сокращения типа I'll такими, какие они есть.
Реализация алгоритма шифрования Цезаря
Юлий Цезарь, римский государственный деятель, защищал сообщения, которые он отправлял своим генералам, зашифровывая их с помощью шифра. В шифре Цезаря каждая буква сдвигается на определенное количество букв. Например, если вы сдвинете букву a на три, то получите букву d и так далее.
Если сдвиг выходит за пределы конца алфавита, то вам просто нужно повернуть обратно к началу алфавита. В случае поворота на три, x станет a. Вот как выглядел бы алфавит после ротации:
- Оригинальный алфавит:
abcdefghijklmnopqrstuvwxyz - Алфавит повернут на три:
defghijklmnopqrstuvwxyzabc
Следующий код реализует rotate_chr(), функцию, которая принимает символ и поворачивает его на три. rotate_chr() вернет повернутый символ. Вот код:
1def rotate_chr(c):
2 rot_by = 3
3 c = c.lower()
4 alphabet = "abcdefghijklmnopqrstuvwxyz"
5 # Keep punctuation and whitespace
6 if c not in alphabet:
7 return c
8 rotated_pos = ord(c) + rot_by
9 # If the rotation is inside the alphabet
10 if rotated_pos <= ord(alphabet[-1]):
11 return chr(rotated_pos)
12 # If the rotation goes beyond the alphabet
13 return chr(rotated_pos - len(alphabet))
Внутри rotate_chr() вы сначала проверяете, есть ли символ в алфавите. Если нет, то вы возвращаете тот же символ. Это делается для того, чтобы сохранить знаки препинания и другие необычные символы. В строке 8 вы вычисляете новое повернутое положение символа в алфавите. Для этого вы используете встроенную функцию ord().
ord() принимает символ Юникода и возвращает целое число, представляющее кодовую точку Юникода входного символа. Например, ord("a") возвращает 97, а ord("b") возвращает 98:
>>> ord("a")
97
>>> ord("b")
98
ord() принимает символ в качестве аргумента и возвращает кодовую точку в Юникоде входного символа.
Если вы добавите это целое число к целевому числу rot_by, то получите повернутую позицию новой буквы в алфавите. В этом примере rot_by равно 3. Таким образом, буква "a", повернутая на три, станет буквой в позиции 100, которая является буквой "d". Буква "b", повернутая на три, станет буквой в позиции 101, которая является буквой "e", и так далее.
Если новая позиция буквы не выходит за пределы позиции последней буквы (alphabet[-1]),, то вы возвращаете букву в это новое положение. Для этого вы используете встроенную функцию chr().
chr() значение, обратное ord(). Оно принимает целое число, представляющее кодовую точку символа Unicode, и возвращает символ в этой позиции. Например, chr(97) вернет 'a', а chr(98) вернет 'b':
>>> chr(97)
'a'
>>> chr(98)
'b'
chr() принимает целое число, представляющее кодовую точку символа в Юникоде, и возвращает соответствующий символ.
Наконец, если новая повернутая позиция находится за пределами позиции последней буквы (alphabet[-1]),, то вам нужно повернуть обратно к началу алфавита. Чтобы сделать это, вам нужно вычесть длину алфавита из повернутого положения (rotated_pos - len(alphabet)), а затем вернуть букву в это новое положение, используя chr().
Используя rotate_chr() в качестве функции преобразования, вы можете использовать map() для шифрования любого текста с помощью алгоритма шифрования Цезаря. Вот пример, в котором для объединения строки используется str.join():
>>> "".join(map(rotate_chr, "My secret message goes here."))
'pb vhfuhw phvvdjh jrhv khuh.'
Строки в Python также являются повторяемыми. Таким образом, вызов map() применяется rotate_chr() к каждому символу в исходной входной строке. В этом случае "M" становится "p", "y" становится "b" и так далее. Наконец, вызов str.join() объединяет все повернутые символы в конечном зашифрованном сообщении.
Преобразование повторяющихся чисел с помощью Python map()
map() также обладает большим потенциалом, когда дело доходит до обработки и преобразования повторяющихся значений числовых значений. Вы можете выполнять широкий спектр математических и арифметических операций, преобразовывать строковые значения в числа с плавающей запятой или целые числа и так далее.
В следующих разделах вы рассмотрите несколько примеров использования map() для обработки и преобразования повторяющихся чисел.
Использование математических операций
Распространенным примером использования математических операций для преобразования итерационных числовых значений является использование оператора power (**). В следующем примере вы кодируете функцию преобразования, которая принимает число и возвращает число в квадрате и кубе:
>>> def powers(x):
... return x ** 2, x ** 3
...
>>> numbers = [1, 2, 3, 4]
>>> list(map(powers, numbers))
[(1, 1), (4, 8), (9, 27), (16, 64)]
powers() принимает число x и возвращает его квадрат и куб. Поскольку Python обрабатывает несколько возвращаемых значений в виде кортежей, каждый вызов powers() возвращает кортеж с двумя значениями. Когда вы вызываете map() с powers() в качестве аргумента, вы получаете список кортежей, содержащих квадрат и куб каждого числа во входной итерации.
Существует множество математических преобразований, которые можно выполнить с помощью map(). Вы можете добавлять константы к каждому значению и вычитать их из него. Вы также можете использовать некоторые функции из модуля math, такие как sqrt(), factorial(), sin(), cos(), и так далее. Вот пример использования factorial():
>>> import math
>>> numbers = [1, 2, 3, 4, 5, 6, 7]
>>> list(map(math.factorial, numbers))
[1, 2, 6, 24, 120, 720, 5040]
В этом случае вы преобразуете numbers в новый список, содержащий факториал каждого числа из исходного списка.
Вы можете выполнять широкий спектр математических преобразований с повторяющимися числами, используя map(). Насколько глубоко вы углубитесь в эту тему, будет зависеть от ваших потребностей и вашего воображения. Подумайте и придумайте свои собственные примеры!
Преобразование температур
Другим вариантом использования map() является преобразование между единицами измерения. Предположим, у вас есть список температур, измеренных в градусах Цельсия или Фаренгейта, и вам нужно преобразовать их в соответствующие температуры в градусах Фаренгейта или Цельсия.
Для выполнения этой задачи вы можете запрограммировать две функции преобразования:
def to_fahrenheit(c):
return 9 / 5 * c + 32
def to_celsius(f):
return (f - 32) * 5 / 9
to_fahrenheit() измеряет температуру в градусах Цельсия и преобразует ее в градусы Фаренгейта. Аналогично, to_celsius() измеряет температуру в градусах Фаренгейта и преобразует ее в градусы Цельсия.
Эти функции будут вашими функциями преобразования. Вы можете использовать их с помощью map() для преобразования повторяющихся значений температуры в градусы Фаренгейта и Цельсия соответственно:
>>> celsius_temps = [100, 40, 80]
>>> # Convert to Fahrenheit
>>> list(map(to_fahrenheit, celsius_temps))
[212.0, 104.0, 176.0]
>>> fahr_temps = [212, 104, 176]
>>> # Convert to Celsius
>>> list(map(to_celsius, fahr_temps))
[100.0, 40.0, 80.0]
Если вы наберете map() с помощью to_fahrenheit() и celsius_temps, то получите список значений температуры в градусах Фаренгейта. Если вы наберете map() с помощью to_celsius() и fahr_temps, то получите список значений температуры в градусах Цельсия.
Чтобы расширить этот пример и охватить любой другой вид преобразования единиц измерения, вам просто нужно закодировать соответствующую функцию преобразования.
Преобразование строк в числа
При работе с числовыми данными вы, скорее всего, столкнетесь с ситуациями, в которых все ваши данные являются строковыми значениями. Для выполнения дальнейших вычислений вам потребуется преобразовать строковые значения в числовые. map() может помочь и в этих ситуациях.
Если вы уверены, что ваши данные чисты и не содержат неправильных значений, то вы можете использовать float() или int() непосредственно в соответствии с вашими потребностями . Вот несколько примеров:
>>> # Convert to floating-point
>>> list(map(float, ["12.3", "3.3", "-15.2"]))
[12.3, 3.3, -15.2]
>>> # Convert to integer
>>> list(map(int, ["12", "3", "-15"]))
[12, 3, -15]
В первом примере вы используете float() с map() для преобразования всех значений из строковых в значения с плавающей запятой. Во втором случае вы используете int() для преобразования из строки в целое число. Обратите внимание, что если одно из значений не является допустимым числом, то вы получите ValueError.
Если вы не уверены в чистоте ваших данных, то можете использовать более сложную функцию преобразования, например, следующую:
>>> def to_float(number):
... try:
... return float(number.replace(",", "."))
... except ValueError:
... return float("nan")
...
>>> list(map(to_float, ["12.3", "3,3", "-15.2", "One"]))
[12.3, 3.3, -15.2, nan]
Внутри to_float() используется try оператор, который перехватывает ValueError, если float() не выполняется при преобразовании number. Если ошибки не возникает, то ваша функция возвращает number, преобразованное в допустимое число с плавающей запятой. В противном случае вы получите nan ( Не числовое) значение, которое является специальным значением float, которое можно использовать для представления значений, которые не являются допустимыми числами, точно так же, как "One" в приведенном выше примере.
Вы можете настроить to_float() в соответствии со своими потребностями. Например, вы можете заменить оператор return float("nan") на оператор return 0.0 и так далее.
Комбинирование map() С другими Функциональными Инструментами
До сих пор вы описывали, как использовать map() для выполнения различных задач, связанных с итерациями. Однако, если вы используете map() вместе с другими функциональными инструментами, такими как filter() и reduce(), то вы можете выполнять более сложные преобразования с вашими повторяющимися объектами. Это то, о чем вы расскажете в следующих двух разделах.
map() и filter()
Иногда вам нужно обработать входную итерацию и вернуть другую итерацию, которая является результатом фильтрации нежелательных значений во входной итерации. В этом случае хорошим вариантом для вас может быть функция Python filter(). filter() - это встроенная функция, которая принимает два позиционных аргумента:
functionбудет предикатом или логически значимой функцией, которая возвращаетTrueилиFalseв соответствии с входными данными.iterableбудет доступен для любой итерации на Python.
filter() возвращает элементы входных данных iterable, для которых function возвращает True. Если вы передаете None в function, то filter() использует функцию идентификации. Это означает, что filter() проверит истинность каждого элемента в iterable и отфильтрует все элементы, которые являются ложными.
Чтобы проиллюстрировать, как вы можете использовать map() вместе с filter(), предположим, вам нужно вычислить квадратный корень из всех значений в списке. Поскольку ваш список может содержать отрицательные значения, вы получите сообщение об ошибке, поскольку квадратный корень не определен для отрицательных чисел:
>>> import math
>>> math.sqrt(-16)
Traceback (most recent call last):
File "<input>", line 1, in <module>
math.sqrt(-16)
ValueError: math domain error
С отрицательным числом в качестве аргумента, math.sqrt() вызывает ValueError. Чтобы избежать этой проблемы, вы можете использовать filter(), чтобы отфильтровать все отрицательные значения, а затем найти квадратный корень из оставшихся положительных значений. Посмотрите следующий пример:
>>> import math
>>> def is_positive(num):
... return num >= 0
...
>>> def sanitized_sqrt(numbers):
... cleaned_iter = map(math.sqrt, filter(is_positive, numbers))
... return list(cleaned_iter)
...
>>> sanitized_sqrt([25, 9, 81, -16, 0])
[5.0, 3.0, 9.0, 0.0]
is_positive() это функция-предикат, которая принимает число в качестве аргумента и возвращает True, если число больше или равно нулю. Вы можете передать is_positive() в filter(), чтобы удалить все отрицательные числа из numbers. Таким образом, вызов map() будет обрабатывать только положительные числа, а math.sqrt() не даст вам результата. ValueError.
map() и reduce()
Python reduce() - это функция, которая находится в модуле с именем functools в стандартной библиотеке Python. reduce() это еще один базовый функциональный инструмент в Python, который полезен, когда вам нужно применить функцию к итерируемому объекту и свести его к одному суммарному значению. Этот вид операции обычно известен как сокращение или сворачивание. reduce() принимает два обязательных аргумента:
functionможет быть любым вызываемым объектом Python, который принимает два аргумента и возвращает значение.iterableможет быть любым, повторяемым на Python.
reduce() применит function ко всем элементам в iterable и суммарно вычислит конечное значение.
Вот пример, который объединяет map() и reduce(), чтобы рассчитать общий размер всех файлов, которые находятся в вашем домашнем каталоге, в совокупности:
>>> import functools
>>> import operator
>>> import os
>>> files = os.listdir(os.path.expanduser("~"))
>>> functools.reduce(operator.add, map(os.path.getsize, files))
4377381
В этом примере вы вызываете os.path.expanduser("~"), чтобы получить путь к вашему домашнему каталогу. Затем вы вызываете os.listdir() по этому пути, чтобы получить список с путями ко всем файлам, которые там находятся.
При вызове map() используется os.path.getsize() для получения размера каждого файла. Наконец, вы используете reduce() с помощью operator.add(), чтобы получить суммарный размер каждого отдельного файла. Конечным результатом является общий размер всех файлов в вашем домашнем каталоге в байтах.
Примечание: Несколько лет назад Google разработала и начала использовать модель программирования, которую они назвали MapReduce. Это был новый стиль обработки данных, предназначенный для управления большими данными с использованием параллельных и распределенных вычислений в кластере .
Эта модель была основана на сочетании операций map и reduce, обычно используемых в функциональном программировании.
Модель MapReduce оказала огромное влияние на способность Google обрабатывать огромные объемы данных в разумные сроки. Однако к 2014 году Google больше не использовала MapReduce в качестве основной модели обработки.
В настоящее время вы можете найти несколько альтернативных реализаций MapReduce, таких как Apache Hadoop, который представляет собой набор программных утилит с открытым исходным кодом, использующих модель MapReduce.
Несмотря на то, что вы можете использовать reduce() для решения проблемы, описанной в этом разделе, Python предлагает другие инструменты, которые могут привести к более понятному и эффективному решению. Например, вы можете использовать встроенную функцию sum() для вычисления общего размера файлов в вашем домашнем каталоге:
>>> import os
>>> files = os.listdir(os.path.expanduser("~"))
>>> sum(map(os.path.getsize, files))
4377381
Этот пример намного более удобочитаем и эффективен, чем тот, который вы видели ранее. Если вы хотите глубже разобраться в том, как использовать reduce() и какие альтернативные инструменты вы можете использовать для замены reduce() на языке Python, ознакомьтесь с Python's reduce(): от функционального к питоновскому стилю.
Обработка итераций на основе кортежей С помощью starmap()
В Python itertools.starmap() создается итератор, который применяет функцию к аргументам, полученным из итерируемого набора кортежей, и выдает результаты. Это полезно, когда вы обрабатываете повторяющиеся объекты, которые уже сгруппированы в кортежи.
Основное различие между map() и starmap() заключается в том, что последний вызывает свою функцию преобразования, используя оператор распаковки (*), чтобы распаковать каждый набор аргументов на несколько позиционных аргументов. Таким образом, функция преобразования вызывается как function(*args) вместо function(arg1, arg2,... argN).
В официальной документации для starmap() говорится, что эта функция примерно эквивалентна следующей функции Python:
def starmap(function, iterable):
for args in iterable:
yield function(*args)
Цикл for в этой функции выполняет итерацию по элементам в iterable и в результате выдает преобразованные элементы. Вызов function(*args) использует оператор распаковки, чтобы разложить кортежи на несколько позиционных аргументов. Вот несколько примеров того, как работает starmap():
>>> from itertools import starmap
>>> list(starmap(pow, [(2, 7), (4, 3)]))
[128, 64]
>>> list(starmap(ord, [(2, 7), (4, 3)]))
Traceback (most recent call last):
File "<input>", line 1, in <module>
list(starmap(ord, [(2, 7), (4, 3)]))
TypeError: ord() takes exactly one argument (2 given)
В первом примере вы используете pow() для вычисления степени первого значения, возведенного во второе значение в каждом кортеже. Кортежи будут иметь следующий вид (base, exponent).
Если каждый кортеж в вашей итерируемой таблице содержит два элемента, то function также должен принимать два аргумента. Если в кортежах три элемента, то function должен принимать три аргумента и так далее. В противном случае вы получите TypeError.
Если вы используете map() вместо starmap(), то вы получите другой результат, потому что map() берет по одному элементу из каждого кортежа:
>>> list(map(pow, (2, 7), (4, 3)))
[16, 343]
Обратите внимание, что map() принимает два кортежа вместо списка кортежей. map() также принимает по одному значению из каждого кортежа на каждой итерации. Чтобы map() возвращал тот же результат, что и starmap(), вам нужно поменять местами значения:
>>> list(map(pow, (2, 4), (7, 3)))
[128, 64]
В этом случае у вас есть два кортежа вместо списка кортежей. Вы также поменяли местами 7 и 4. Теперь первый кортеж содержит основания, а второй кортеж - экспоненты.
Кодирование в стиле Python: Замена map()
Инструменты функционального программирования, такие как map(), filter(), и reduce(), существуют уже давно. Тем не менее, списки значений и генераторные выражения стали естественной заменой им почти в каждом случае использования.
Например, функциональность, предоставляемая map(), почти всегда лучше выражается с помощью понимания списка или генераторного выражения. В следующих двух разделах вы узнаете, как заменить вызов map() понятием списка или генераторным выражением, чтобы сделать ваш код более читабельным и основанным на Python.
Использование значений списка
Существует общий шаблон, который вы можете использовать, чтобы заменить вызов map() на использование списка. Вот как:
# Generating a list with map
list(map(function, iterable))
# Generating a list with a list comprehension
[function(x) for x in iterable]
Обратите внимание, что понимание списка почти всегда читается более четко, чем вызов map(). Поскольку понимание списка довольно популярно среди разработчиков Python, его часто можно найти повсюду. Таким образом, замена вызова map() на использование списка сделает ваш код более знакомым для других разработчиков на Python.
Вот пример того, как заменить map() на понимание списка, чтобы построить список квадратных чисел:
>>> # Transformation function
>>> def square(number):
... return number ** 2
>>> numbers = [1, 2, 3, 4, 5, 6]
>>> # Using map()
>>> list(map(square, numbers))
[1, 4, 9, 16, 25, 36]
>>> # Using a list comprehension
>>> [square(x) for x in numbers]
[1, 4, 9, 16, 25, 36]
Если вы сравните оба решения, то можете сказать, что то, в котором используется понимание списка, более читабельно, потому что оно читается почти как обычный английский. Кроме того, при составлении списков нет необходимости явно вызывать list() для map() для создания окончательного списка.
Использование генераторных выражений
map() возвращает объект карты, который является итератором, выдающим элементы по запросу. Таким образом, естественной заменой map() является генераторное выражение, поскольку генераторные выражения возвращают объекты-генераторы, которые также являются итераторами, выдающими элементы по запросу.
Известно, что итераторы Python довольно эффективны с точки зрения потребления памяти. Именно по этой причине map() теперь возвращает итератор вместо list.
Существует небольшая синтаксическая разница между понятием списка и выражением-генератором. В первом случае для разграничения выражения используется пара квадратных скобок ([]). Во втором случае используется пара круглых скобок (()). Итак, чтобы преобразовать представление списка в генераторное выражение, вам просто нужно заменить квадратные скобки круглыми скобками.
Вы можете использовать генераторные выражения для написания кода, который читается понятнее, чем код, использующий map(). Ознакомьтесь со следующим примером:
>>> # Transformation function
>>> def square(number):
... return number ** 2
>>> numbers = [1, 2, 3, 4, 5, 6]
>>> # Using map()
>>> map_obj = map(square, numbers)
>>> map_obj
<map object at 0x7f254d180a60>
>>> list(map_obj)
[1, 4, 9, 16, 25, 36]
>>> # Using a generator expression
>>> gen_exp = (square(x) for x in numbers)
>>> gen_exp
<generator object <genexpr> at 0x7f254e056890>
>>> list(gen_exp)
[1, 4, 9, 16, 25, 36]
Этот код имеет основное отличие от кода в предыдущем разделе: вы заменяете квадратные скобки на пару круглых скобок, чтобы превратить понимание списка в выражение генератора.
Генераторные выражения обычно используются в качестве аргументов при вызове функций. В этом случае вам не нужно использовать круглые скобки для создания генераторного выражения, поскольку круглые скобки, которые вы используете для вызова функции, также предоставляют синтаксис для создания генератора. Используя эту идею, вы можете получить тот же результат, что и в приведенном выше примере, вызвав list() следующим образом:
>>> list(square(x) for x in numbers)
[1, 4, 9, 16, 25, 36]
Если вы используете генераторное выражение в качестве аргумента при вызове функции, то вам не нужна дополнительная пара круглых скобок. Круглые скобки, которые вы используете для вызова функции, предоставляют синтаксис для построения генератора.
Генераторные выражения так же эффективны, как и map(), с точки зрения потребления памяти, поскольку оба они возвращают итераторы, которые выдают элементы по запросу. Однако генераторные выражения почти всегда улучшают читаемость вашего кода. Они также делают ваш код более понятным в глазах других разработчиков на Python.
Заключение
Программа Python map() позволяет выполнять операции сопоставления с повторяющимися объектами. Операция сопоставления состоит в применении функции преобразования к элементам в iterable для создания преобразованной iterable. В общем, map() позволит вам обрабатывать и преобразовывать повторяющиеся объекты без использования явного цикла.
В этом руководстве вы узнали, как работает map() и как использовать его для обработки повторяющихся элементов. Вы также узнали о некоторых инструментах Python, которые можно использовать для замены map() в вашем коде.
Теперь вы знаете, как:
- Работа с Python'ами
map() - Используйте
map()для обработки и преобразования итераций без использования явного цикла - Комбинируйте
map()с такими функциями, какfilter()иreduce(), для выполнения сложных преобразований - Замените
map()на такие инструменты, как составление списков и генераторные выражения
Благодаря этим новым знаниям вы сможете использовать map() в своем коде и подходить к нему с функциональным стилем программирования. Вы также можете перейти к более современному питоновскому стилю, заменив map() на для понимания списка или на генераторное выражение.
<статус завершения article-slug="python-map-function" class="btn-group mb-0" data-api-article-bookmark-url="/api/v1/articles/python-map-function/bookmark/" данные-api-статья-статус завершения-url="/api/v1/articles/python-map-function/completion_status/"> статус завершения> <поделиться-кнопка bluesky-text="Интересная статья #Python от @realpython.com :" email-body="Ознакомьтесь с этой статьей о Python:%0A%0apython's map(): Обработка итераций без цикла" email-subject="Статья на Python для вас" twitter-text="Интересная статья на #Python от @realpython:" url="https://realpython.com/python-map-function /" url-title="Python's map(): обработка итераций без цикла"> кнопка поделиться>
Смотрите сейчас, к этому уроку прилагается соответствующий видеокурс, созданный командой Real Python. Посмотрите его вместе с письменным руководством, чтобы углубить свое понимание: Функция map() в Python: преобразование повторяемых объектов
Back to Top