Django-Admin.ru

map() в Python: применение функции к каждому элементу

Как работает map в Python: map(func, iterable), несколько списков, ленивость и list(), map(int, input().split()), lambda, map или list comprehension, filter.

Редакция Django-Admin.ru
· обновлено · 11 мин чтения

Содержание · 11 разделов
  1. Синтаксис map
  2. map со встроенными функциями и методами
  3. map(int, input().split()): ввод чисел в одну строку
  4. Несколько итерируемых объектов
  5. Ленивость: почему map нужно превращать в list
  6. map и словари
  7. map или списковое включение: что выбрать
  8. filter: отбор элементов
  9. Частые ошибки
  10. Вывод <map object at 0x...> вместо значений
  11. Скобки после имени функции
  12. Число аргументов не совпадает с числом списков
  13. Повторное использование объекта map
  14. len() и индексация
  15. Ошибка появляется «не там»
  16. Частые вопросы
  17. Как передать функции в map дополнительный аргумент?
  18. Как прочитать числа, записанные через запятую?
  19. Как прочитать числа, если каждое стоит на отдельной строке?
  20. Это то же самое, что map в C++ или Java?
  21. Итог

map() в Python — встроенная функция, которая применяет другую функцию к каждому элементу итерируемого объекта и возвращает результаты по одному. Самый частый пример — превратить строки в числа:

numbers = ["1", "2", "3"]

result = map(int, numbers)
print(list(result))  # → [1, 2, 3]

Главное, что нужно запомнить: map возвращает не список, а ленивый объект map, поэтому для вывода и повторного использования его оборачивают в list(). Ниже — синтаксис, работа с несколькими списками, разбор map(int, input().split()), сравнение со списковым включением и типичные ошибки. Примеры проверены на Python 3.12.

Синтаксис map

map(function, iterable, *iterables)
map(function, iterable, *iterables, strict=False)  # Python 3.14+
  • function — функция, которую нужно применить. Передаётся сама функция, без скобок: int, а не int().
  • iterable — список, кортеж, строка, словарь, файл или другой итерируемый объект.
  • *iterables — дополнительные последовательности, если функция принимает несколько аргументов.
  • strict — только именованный, появился в Python 3.14: при strict=True последовательности разной длины вызывают ValueError.

Функцией может быть встроенная функция, ваша собственная функция, метод класса или lambda:

def square(x):
    return x * x

print(list(map(square, [1, 2, 3, 4])))          # → [1, 4, 9, 16]
print(list(map(lambda x: x * x, [1, 2, 3, 4])))  # → [1, 4, 9, 16]

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

map со встроенными функциями и методами

Сильнее всего map выглядит, когда функция уже существует и не нужна lambda:

words = ["python", "django", "fastapi"]

print(list(map(str.upper, words)))   # → ['PYTHON', 'DJANGO', 'FASTAPI']
print(list(map(len, words)))         # → [6, 6, 7]
print(list(map(str, [1, 2, 3])))     # → ['1', '2', '3']
print(list(map(float, ["3.14", "2"])))  # → [3.14, 2.0]
print(list(map(abs, [-3, 0, 2])))    # → [3, 0, 2]
print(list(map(str.strip, ["  a ", "b  ", " c"])))  # → ['a', 'b', 'c']

В str.upper и str.strip метод вызывается через класс, а каждый элемент подставляется как self. Так можно использовать любой метод без аргументов.

Классический приём — склеить числа в строку. Метод join принимает только строки, поэтому числа сначала проходят через map(str, ...):

print(" ".join(map(str, [1, 2, 3])))  # → 1 2 3

Подробнее о склейке строк — в статье про метод join().

map(int, input().split()): ввод чисел в одну строку

Эту конструкцию встречает каждый, кто решает олимпиадные или учебные задачи. Разберём её по шагам на вводе 3 5:

  1. input() читает строку: "3 5".
  2. .split() делит её по пробелам: ["3", "5"].
  3. map(int, ...) применяет int к каждой части и выдаёт 3 и 5.
  4. Результат распаковывается в переменные или собирается в список.
a, b = map(int, input().split())
print(a + b)
# ввод:  3 5
# вывод: 8

numbers = list(map(int, input().split()))
print(numbers, sum(numbers))
# ввод:  10 20 30 40
# вывод: [10, 20, 30, 40] 100

Распаковка a, b = ... работает и без list(): Python сам переберёт объект map. Но количество чисел во вводе должно совпадать с числом переменных — при вводе 1 2 3 будет ValueError: too many values to unpack (expected 2).

Без .split() map пройдёт по строке посимвольно, и int упадёт на пробеле:

list(map(int, "12 5"))          # ValueError: invalid literal for int() with base 10: ' '
list(map(int, "12 5".split()))  # → [12, 5]

Как устроен split() и его аргументы — в статье про split() в Python.

Несколько итерируемых объектов

Если передать несколько последовательностей, функция получит по одному элементу из каждой — так же, как в zip(). Число аргументов функции должно совпадать с числом последовательностей:

a = [1, 2, 3]
b = [10, 20, 30]

print(list(map(lambda x, y: x + y, a, b)))  # → [11, 22, 33]
print(list(map(pow, [2, 3, 4], [3, 2, 1]))) # → [8, 9, 4]   2**3, 3**2, 4**1
print(list(map(max, [1, 5, 3], [4, 2, 6]))) # → [4, 5, 6]

Вместо lambda x, y: x + y можно взять готовую функцию из модуля operator: map(operator.add, a, b).

Важно: map останавливается на самой короткой последовательности. Лишние элементы молча отбрасываются, ошибки не будет:

print(list(map(lambda x, y: x * y, [1, 2, 3], [10, 20])))  # → [10, 40]

В Python 3.14 у map появился параметр strict, как у zip() с версии 3.10. С strict=True разная длина последовательностей вызывает ошибку, и потерянные данные не останутся незамеченными:

# Python 3.14+
list(map(lambda x, y: x * y, [1, 2, 3], [10, 20], strict=True))
# ValueError: map() argument 2 is shorter than argument 1

В версиях до 3.14 параметра нет, и такой вызов завершится TypeError (в Python 3.12 — map() takes no keyword arguments).

Если данные уже лежат парами — списком кортежей, — используйте itertools.starmap, он распаковывает каждый кортеж в аргументы:

from itertools import starmap

print(list(starmap(pow, [(2, 3), (3, 2)])))  # → [8, 9]

Ленивость: почему map нужно превращать в list

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

def noisy(x):
    print("обрабатываю", x)
    return x * 10

m = map(noisy, [1, 2, 3])
print("map создан")
print(next(m))
print(list(m))
print(list(m))
map создан
обрабатываю 1
10
обрабатываю 2
обрабатываю 3
[20, 30]
[]

Из этого примера видно три свойства:

  • Вычисление откладывается. Пока вы не начали перебор, функция не вызвана ни разу. Поэтому ошибка в данных проявится не на строке с map, а позже — там, где результат используется.
  • Объект одноразовый. После полного прохода итератор пуст, второй list(m) вернёт [].
  • Экономия памяти. Промежуточный список не создаётся, что важно для больших файлов и длинных последовательностей.

Если результат нужен целиком или несколько раз — сохраните его: list(map(...)), tuple(map(...)) или set(map(...)). Если он сразу передаётся в функцию, которая сама перебирает элементы, list() не нужен:

print(sum(map(int, ["10", "20", "30"])))  # → 60
print(max(map(len, words)))               # → 7

for n in map(int, ["7", "8"]):
    print(n)
# → 7
# → 8

map и словари

При переборе словаря map получает ключи. Для значений передайте d.values(), для пар — d.items():

prices = {"кофе": 150, "чай": 90}

print(list(map(str.upper, prices)))  # → ['КОФЕ', 'ЧАЙ']
print(list(map(lambda kv: f"{kv[0]}: {kv[1]} ₽", prices.items())))
# → ['кофе: 150 ₽', 'чай: 90 ₽']

Чтобы получить новый словарь, генератор словаря обычно читается лучше, чем комбинация dict, zip и map: {name: price * 2 for name, price in prices.items()}. Подробнее — в статье про словари в Python.

map или списковое включение: что выбрать

Почти любой map можно переписать как списковое включение (list comprehension):

list(map(int, numbers))                 # → [1, 2, 3]
[int(s) for s in numbers]               # → [1, 2, 3]

list(map(lambda x: x * x, [1, 2, 3, 4])) # → [1, 4, 9, 16]
[x * x for x in [1, 2, 3, 4]]            # → [1, 4, 9, 16]
СитуацияЛучше
Готовая функция: int, str, len, str.stripmap(int, items) — коротко и ясно
Нужно выражение — пришлось бы писать lambdaвключение [x * 2 for x in items]
Нужна фильтрация по условиювключение с if
Результат перебирается один раз, список не нуженmap или генераторное выражение (… for …)
Нужен словарь или множествогенератор словаря или множества

По скорости разница невелика и не должна быть главным аргументом. Пример одного замера timeit на Python 3.12 и списке из 10 000 элементов: list(map(int, s)) — около 1,1 мс, [int(x) for x in s] — около 1,5 мс; map с lambda x: x * 2 — около 1 мс против 0,4 мс у включения [x * 2 for x in n]. Для lambda на каждый элемент вызывается дополнительная Python-функция, поэтому такой map обычно проигрывает. Повторите замер на своих данных и версии Python, прежде чем делать выводы.

Практическое правило: есть готовая функция — map, нужно писать lambda — включение.

filter: отбор элементов

filter(function, iterable) — родственник map. Он не преобразует элементы, а оставляет те, для которых функция вернула истинное значение. Результат тоже ленивый:

nums = [1, 2, 3, 4, 5, 6]

print(list(filter(lambda n: n % 2 == 0, nums)))  # → [2, 4, 6]

Если вместо функции передать None, filter уберёт все «ложные» значения — 0, пустые строки и списки, None:

print(list(filter(None, [0, 1, "", "a", None, [], [2]])))  # → [1, 'a', [2]]

map и filter можно комбинировать, но включение с условием обычно читается проще:

print(list(map(lambda n: n * n, filter(lambda n: n % 2 == 0, nums))))  # → [4, 16, 36]
print([n * n for n in nums if n % 2 == 0])                             # → [4, 16, 36]

Частые ошибки

Вывод <map object at 0x...> вместо значений

print(map(int, ["1", "2", "3"]))  # → <map object at 0x000002A51891AE30>

Так Python показывает сам объект-итератор: значения появятся только при обходе. Оберните результат в list().

Скобки после имени функции

list(map(int(), ["1"]))  # TypeError: 'int' object is not callable

int() вызывает функцию и возвращает 0, а map нужна сама функция. Сам вызов map(int(), ...) ошибки не даёт — она появится при переборе результата. Пишите map(int, ...).

Число аргументов не совпадает с числом списков

a = [1, 2]
b = [3, 4]
list(map(lambda x: x * 2, a, b))
# TypeError: <lambda>() takes 1 positional argument but 2 were given

Два списка — значит, функция должна принимать два аргумента.

Повторное использование объекта map

После list(m) или цикла for объект пуст. Если результат нужен дважды, сохраните список: values = list(map(...)).

len() и индексация

len(map(int, ["1"]))   # TypeError: object of type 'map' has no len()
map(int, ["1"])[0]     # TypeError: 'map' object is not subscriptable

Объект map — итератор, а не последовательность. Сначала превратите его в список.

Ошибка появляется «не там»

m = map(int, ["1", "x"])  # ошибки нет
list(m)                   # ValueError: invalid literal for int() with base 10: 'x'

Из-за ленивости traceback указывает на строку, где результат перебирается. Ищите плохие данные во входной последовательности. Как разбирать такие сообщения, рассказано в статье про traceback и ошибки Python.

Частые вопросы

Как передать функции в map дополнительный аргумент?

Зафиксируйте его через lambda или functools.partial. Второй вариант не создаёт новую функцию вручную и удобен для встроенных функций с именованными параметрами.

from functools import partial

prices = [1.2345, 9.876, 3.14159]
print(list(map(lambda x: round(x, 2), prices)))       # → [1.23, 9.88, 3.14]
print(list(map(partial(round, ndigits=2), prices)))   # → [1.23, 9.88, 3.14]

Как прочитать числа, записанные через запятую?

Передайте разделитель в split(","). Пробелы вокруг чисел убирать не нужно: int() сам отбрасывает пробельные символы по краям строки.

print(list(map(int, "10, 20,30".split(","))))  # → [10, 20, 30]

Как прочитать числа, если каждое стоит на отдельной строке?

Если количество строк известно, вызывайте input() в генераторе списка: [int(input()) for _ in range(n)]. Если нет, прочитайте весь ввод сразу: list(map(int, sys.stdin.read().split())) — split() без аргументов делит и по переводам строки.

Это то же самое, что map в C++ или Java?

Нет. В C++ и Java map — структура «ключ — значение», в Python ей соответствует словарь dict. Встроенная функция map() в Python ничего не хранит: она применяет функцию к элементам последовательности.

Итог

map(func, iterable) применяет функцию к каждому элементу и возвращает ленивый итератор: оборачивайте его в list(), когда нужен готовый список. Используйте map с готовыми функциями — int, str, len, методами строк, — а для выражений и фильтрации выбирайте списковое включение. Если вместе с элементом нужен его номер, пригодится функция enumerate(). Остальные встроенные функции и конструкции языка собраны в шпаргалке по синтаксису Python, а потренироваться с map(int, input().split()) можно на задачах по Python с решениями.

  • #Python
  • #map
  • #lambda
  • #filter
  • #Встроенные функции
↑ ↓ выборEnter открытьEsc закрыть