Функция map в Python: зачем нужна и как пользоваться
Функция map() в Python применяет одну и ту же функцию к каждому элементу последовательности и возвращает итератор с результатами. Она заменяет цикл for там, где нужно одинаково преобразовать все элементы: перевести строки в числа, округлить значения, убрать лишние пробелы. Исходная коллекция при этом не меняется.
Ниже разберем синтаксис, рабочие примеры, сравнение с альтернативами и ошибки, на которых спотыкаются новички. Все примеры проверены на Python 3.12; отдельно отмечено, что появилось в версии 3.14.
Коротко о главном
- map() принимает функцию и одну или несколько последовательностей, возвращает ленивый итератор.
- Чтобы увидеть результат, итератор нужно развернуть: list(), tuple(), цикл for или next().
- Итератор одноразовый: после полного прохода он пуст.
- При нескольких последовательностях обработка останавливается по самой короткой. В Python 3.14 появился аргумент strict=True, который вместо молчаливого обрезания выбрасывает ValueError.
- map() реализована на C, поэтому на простых преобразованиях со встроенной функцией она быстрее цикла for.
- Если внутрь просится сложная lambda с условиями, берите генератор списка или обычный цикл.
Что делает функция map() в Python
map() — встроенная функция, доступная сразу, без импортов. Она берет два обязательных элемента: функцию-преобразователь и итерируемый объект, по элементам которого нужно пройти.
Представьте склад, где приняли партию товара и все ценники нужно перевести из долларов в сумы. Можно взять каждый ценник по очереди и пересчитать вручную — это цикл for. А можно отдать всю пачку сотруднику с одной инструкцией «умножь каждое число на курс» — это map().
prices_usd = [12, 45, 8, 120]
rate = 12100
prices_uzs = map(lambda price: price * rate, prices_usd)
print(list(prices_uzs)) # [145200, 544500, 96800, 1452000]
Работает со списками, кортежами, строками, множествами, словарями, файловыми объектами, генераторами и вообще с любым итерируемым объектом.
Почему map() называют функцией высшего порядка
map() принимает другую функцию в качестве аргумента, и это признак функции высшего порядка. Вместе с filter() и reduce() она появилась в Python в 1993 году как набор инструментов функционального программирования.
Ключевая идея этого подхода: функция не меняет исходные данные, а создает новые. map() следует этому правилу буквально: список, который вы передали, останется прежним. Именно поэтому ее называют «чистой»: одни и те же входные данные всегда дают один и тот же результат, а состояние программы не затрагивается.
Синтаксис map()
map(function, iterable, /, *iterables, strict=False)
Разберем аргументы:
- function — функция, которая применяется к каждому элементу. Передается по имени, без круглых скобок. Это может быть встроенная функция, lambda, ваша собственная функция, метод или любой другой вызываемый объект.
- iterable — последовательность, элементы которой обрабатываются.
- *iterables — необязательные дополнительные последовательности.
- strict — появился в Python 3.14. При значении True расхождение длин последовательностей вызывает ValueError вместо тихого обрезания.
Важная деталь: количество параметров функции должно точно совпадать с количеством переданных последовательностей. Иначе Python выбросит TypeError.
def add(x, y):
return x + y
a = [1, 2, 3]
b = [10, 20, 30]
print(list(map(add, a, b))) # [11, 22, 33]
print(list(map(add, a))) # TypeError: add() missing 1 required positional argument: 'y'
Официальное описание функции есть в документации Python.
Как работает map() под капотом
map() не создает готовый список сразу. Она возвращает объект-итератор и вычисляет значения лениво, только в тот момент, когда к ним обращаются.
numbers = [1, 2, 3]
result = map(str, numbers)
print(result) # <map object at 0x7f8b1c0d5f40>
Это не ошибка, а нормальное поведение. Ленивость дает три практических эффекта.
Экономия памяти. Если обрабатывать файл на несколько гигабайт, map() пропускает через себя по одному элементу за раз, а не держит весь массив результатов в оперативной памяти.
Скорость на больших объемах. Внутренний цикл map() реализован на C, поэтому на простых преобразованиях он обычно обгоняет эквивалентный цикл for, написанный на Python.
Ничего не произойдет, пока результат не потребуют. Если итератор не «съесть» циклом, list() или sum(), вычислений просто не будет. Это отдельная ловушка, к которой вернемся в разделе про ошибки.
Как получить результат из map()
Чтобы увидеть значения, итератор нужно развернуть в конкретную структуру данных или перебрать.
words = ["яблоко", "ананас", "черника"]
print(list(map(len, words))) # [6, 6, 7]
print(tuple(map(len, words))) # (6, 6, 7)
print(set(map(len, words))) # {6, 7}
for length in map(len, words):
print(length)
Элементы можно доставать поштучно через next() :
iterator = map(int, ['10', '20', '30'])
print(next(iterator)) # 10
print(next(iterator)) # 20
print(next(iterator)) # 30
Можно распаковать напрямую, если элементов немного:
a, b, c = map(int, "123")
print(a, b, c) # 1 2 3
Из map() собирается любой контейнер, принимающий итерируемый объект, не только список:
print(dict(map(lambda x: (x, x * x), [1, 2, 3]))) # {1: 1, 2: 4, 3: 9}
print(frozenset(map(lambda x: x % 2, [1, 2, 3, 4]))) # frozenset({0, 1})
print(bytearray(map(int, [65, 66, 67]))) # bytearray(b'ABC')
Итератор одноразовый
После первого полного прохода объект map опустеет.
result = map(int, ['1', '2', '3'])
print(list(result)) # [1, 2, 3]
print(list(result)) # [] — итератор уже исчерпан
Если результат нужен несколько раз, сразу сохраните его в список.
map() с разными типами функций
Со встроенными функциями
Самый частый сценарий: приведение типов и базовые преобразования.
print(list(map(int, ['1', '2', '3']))) # [1, 2, 3]
print(list(map(float, ['20', '30.5']))) # [20.0, 30.5]
print(list(map(str, [1, 2, 3]))) # ['1', '2', '3']
print(list(map(round, [1.23, 4.56, 7.89]))) # [1, 5, 8]
print(list(map(abs, [-1, -2, 3, -4]))) # [1, 2, 3, 4]
print(list(map(bool, ['', 'hello', '']))) # [False, True, False]
Работают и функции проверки, например определение типа каждого элемента:
items = [1, 'hello', 3.14, [1, 2], {'a': 1}]
print(list(map(type, items)))
# [<class 'int'>, <class 'str'>, <class 'float'>, <class 'list'>, <class 'dict'>]
С lambda-функциями
Lambda — это короткая безымянная функция, которую удобно писать прямо внутри вызова map() .
numbers = [1, 2, 3, 4]
print(list(map(lambda x: x ** 3, numbers))) # [1, 8, 27, 64]
Тот же код без lambda занимает больше строк, но читается понятнее, когда логика сложнее одной операции:
def cube(x):
return x ** 3
print(list(map(cube, numbers))) # [1, 8, 27, 64]
С собственными функциями
Когда преобразование сложное или используется в нескольких местах программы, выносите его в отдельную функцию.
def total_cost(product):
return product["price"] * product["quantity"]
cart = [
{"name": "Ноутбук", "price": 8500000, "quantity": 2},
{"name": "Мышь", "price": 250000, "quantity": 5},
{"name": "Наушники", "price": 600000, "quantity": 3},
]
print(list(map(total_cost, cart))) # [17000000, 1250000, 1800000]
Разбор корзины с ценами и количеством встречается у backend-разработчика постоянно. На курсе Python студенты собирают на этой логике полноценный интернет-магазин, где подсчет стоимости позиций идет ровно через такие преобразования коллекций.
С функциями из стандартной библиотеки
import math
print(list(map(math.sqrt, [1, 4, 9, 16]))) # [1.0, 2.0, 3.0, 4.0]
print(list(map(math.ceil, [3.14, 2.71, 1.41]))) # [4, 3, 2]
С методами строк
Частая задача при разборе данных: очистка строк.
raw = [" Ташкент ", "Самарканд ", " Бухара "]
print(list(map(str.strip, raw))) # ['Ташкент', 'Самарканд', 'Бухара']
print(list(map(str.upper, ["a", "b"]))) # ['A', 'B']
С методами классов: где ловушка
Логично попробовать передать метод класса напрямую, но так это не сработает.
class Product:
def __init__(self, name, price, quantity):
self.name = name
self.price = price
self.quantity = quantity
def total(self):
return self.price * self.quantity
products = [
Product("Ноутбук", 8500000, 2),
Product("Мышь", 250000, 5),
]
# Не сработает как ожидалось: Product.total — несвязанный метод
totals = list(map(Product.total, products))
Рабочих способа два. Можно обернуть вызов в lambda:
totals = list(map(lambda p: p.total(), products))
print(totals) # [17000000, 1250000]
Второй способ чище: operator.methodcaller.
from operator import methodcaller
totals = list(map(methodcaller("total"), products))
print(totals) # [17000000, 1250000]
Внутри самого класса метод можно передавать через self, там связывание уже произошло:
class Calculator:
def __init__(self, rate):
self.rate = rate
def convert(self, amount):
return amount * self.rate
def convert_all(self, amounts):
return list(map(self.convert, amounts))
print(Calculator(12100).convert_all([12, 45])) # [145200, 544500]
С геттерами вместо lambda
Когда нужно просто вытащить поле, operator дает готовые функции, и код становится короче и работает быстрее, чем с lambda.
from operator import itemgetter, attrgetter
users = [{"name": "Азиз", "age": 24}, {"name": "Дилноза", "age": 31}]
print(list(map(itemgetter("name"), users))) # ['Азиз', 'Дилноза']
print(list(map(attrgetter("name"), products))) # ['Ноутбук', 'Мышь' ]
map() с несколькими последовательностями
Если передать две и более последовательности, map() возьмет первые элементы из каждой, потом вторые и так далее.
names = ["Азиз", "Дилноза", "Тимур"]
scores = [88, 95, 72]
result = map(lambda name, score: f"{name}: {score} баллов", names, scores)
print(list(result))
# ['Азиз: 88 баллов', 'Дилноза: 95 баллов', 'Тимур: 72 баллов']
Встроенные функции с двумя аргументами работают так же, например pow():
bases = [2, 3, 10]
exponents = [5, 2, 3]
print(list(map(pow, bases, exponents))) # [32, 9, 1000]
Число последовательностей не ограничено двумя, главное, чтобы функция принимала столько же аргументов.
Разная длина: тихая потеря данных
По умолчанию обработка останавливается на самой короткой последовательности. Ошибки не будет, лишние элементы просто исчезнут.
a = [1, 2, 3, 4, 5]
b = [10, 20]
print(list(map(lambda x, y: x + y, a, b))) # [11, 22]
Это поведение легко пропустить и потерять часть данных. В Python 3.14 появилось решение: аргумент strict .
# Python 3.14+
result = list(map(lambda x, y: x + y, a, b, strict=True))
# ValueError: map() argument 2 is shorter than argument 1
На версиях ниже 3.14 аналогичный контроль делают через zip(..., strict=True) : строгий режим у zip() доступен с Python 3.10. Либо просто проверяйте длины до вызова.
Когда аргументы уже упакованы в кортежи
map() ждет «параллельные» последовательности. Если данные уже лежат парами, нужна itertools.starmap():
from itertools import starmap
pairs = [(2, 5), (3, 2), (10, 3)]
print(list(starmap(pow, pairs))) # [32, 9, 1000]
map(), filter() и reduce(): в чем разница
Три функции решают разные задачи и хорошо работают вместе.
map() — преобразует каждый элемент, количество элементов на выходе то же самое.
print(list(map(lambda x: x * 2, [1, 2, 3, 4]))) # [2, 4, 6, 8]
filter() — отбирает элементы по условию, количество элементов уменьшается.
print(list(filter(lambda x: x % 2 == 0, [1, 2, 3, 4]))) # [2, 4]
reduce() — сворачивает всю последовательность в одно значение. Живет в модуле functools, ее нужно импортировать.
from functools import reduce
print(reduce(lambda acc, x: acc + x, [1, 2, 3, 4])) # 10
Их можно комбинировать: сначала отфильтровать, потом преобразовать, потом свернуть.
from functools import reduce
numbers = [1, 2, 3, 4, 5, 6]
# квадраты четных чисел
print(list(map(lambda x: x ** 2, filter(lambda x: x % 2 == 0, numbers)))) # [4, 16, 36]
# произведение квадратов нечетных
result = reduce(
lambda x, y: x * y,
map(lambda x: x ** 2, filter(lambda x: x % 2 != 0, numbers))
)
print(result) # 225
Отсюда, кстати, и название модели распределенных вычислений MapReduce: сначала данные преобразуются, потом сворачиваются в итог.
map() или list comprehension: что выбрать
Оба инструмента решают одну задачу, и в большинстве случаев результат идентичен.
numbers = [1, 2, 3, 4]
squares_map = list(map(lambda x: x ** 2, numbers))
squares_lc = [x ** 2 for x in numbers]
Различия сводятся к нескольким пунктам. map() возвращает ленивый итератор, генератор списка — сразу готовый список. map() реализована на C и на простых преобразованиях быстрее. map() умеет параллельно обходить несколько последовательностей, генератору списка для этого понадобится zip(). Зато генератор списка принимает произвольное выражение и условие фильтрации прямо в конструкции, а map() требует готовую функцию.
Берите map(), если:
- преобразование — это готовая функция, которую можно передать по имени: map(int, data) короче и быстрее, чем [int(x) for x in data];
- нужно параллельно пройти по нескольким последовательностям;
- строится ленивый конвейер обработки и промежуточные списки не нужны.
Берите list comprehension, если:
- внутри нужно условие: [x ** 2 for x in numbers if x > 2] читается лучше, чем связка map() и filter();
- преобразование пишется выражением, а не отдельной функцией;
- код читают новички: в сообществе Python генераторные выражения считаются более привычным стилем.
Берите обычный цикл for, если:
- логика ветвится, есть несколько условий и промежуточных переменных;
- нужна обработка исключений для отдельных элементов;
- внутри происходят побочные действия: запись в файл, вывод на экран, запрос к базе.
Общий ориентир — принцип из The Zen of Python: простое лучше сложного. Если строка с map() и вложенными lambda перестала читаться с первого раза, перепишите ее циклом.
Умение выбирать между несколькими одинаково рабочими решениями отличает разработчика от человека, который просто выучил синтаксис. Если вам интересно, насколько такой тип задач вообще подходит по складу мышления, это можно проверить на бесплатном IT-тесте. Он занимает несколько минут и показывает, какое направление в IT ближе.
Слабые места map()
У функции есть ограничения, о которых честно стоит знать до того, как встроите ее в проект.
Нет встроенной обработки ошибок . Если функция преобразования упадет на одном элементе, весь map() остановится. Лечится оберткой:
def safe_int(value):
try:
return int(value)
except ValueError:
return None
print(list(map(safe_int, ['1', 'абв', '2']))) # [1, None, 2]
Трудная отладка . В цикле for легко поставить точку останова и посмотреть промежуточные значения. Внутри lambda в map() это неудобно. Помогает itertools.islice(): посмотреть первые несколько элементов, не вычисляя все:
from itertools import islice
preview = list(islice(map(int, ['1', '2', '3', '4', '5']), 3))
print(preview) # [1, 2, 3]
Плохо подходит для вложенных структур . Списки внутри списков через map() разбирать неудобно, читаемее сделать это циклом или comprehension.
Не подходит, когда меняется структура данных. Если из одного элемента должно получиться несколько или наоборот, map() не тот инструмент: она всегда дает «один к одному».
Типичные ошибки новичков
Функция передается со скобками . Так вы передаете не саму функцию, а результат ее вызова.
print(list(map(len(), words))) # TypeError
print(list(map(len, words))) # правильно
Попытка вывести map-объект напрямую . print(map(...)) покажет служебную строку вместо данных, оберните в list().
Повторное обращение к исчерпанному итератору . Второй list() вернет пустой список. Сохраняйте результат в переменную.
Несовпадение числа аргументов и последовательностей . Функция на два параметра требует ровно две последовательности, иначе TypeError.
Потеря данных при разной длине списков . map() молча обрежет обработку по самому короткому. На Python 3.14+ страхуйтесь через strict=True.
Побочные эффекты внутри map() . Функция, которая ничего не возвращает, а только печатает, даст список из None. Хуже того, из-за ленивости она может вообще ничего не сделать, если итератор не потребить:
map(print, [1, 2, 3]) # ничего не выведет
result = list(map(print, [1, 2, 3])) # выведет, но result = [None, None, None]
Для действий, а не преобразований, используйте обычный цикл.
Практика: разбор данных из формы
Допустим, из формы приходит строка с оценками через запятую, а нужно посчитать средний балл.
raw_input_data = " 88, 95 ,72, 64 ,90 "
# Разбиваем строку, убираем пробелы, приводим к числам
scores = list(map(int, map(str.strip, raw_input_data.split(","))))
print(scores) # [88, 95, 72, 64, 90]
print(sum(scores) / len(scores)) # 81.8
Здесь два map() работают в связке: внутренний чистит пробелы, внешний превращает строки в числа.
Практика: обработка большого файла без загрузки в память
Здесь ленивость map() становится не украшением, а необходимостью: файл может не поместиться в оперативную память целиком.
with open("data.txt", encoding="utf-8") as f:
lines = map(str.strip, f) # чистим строки лениво
numbers = map(safe_int, lines) # приводим к числам
valid = filter(lambda x: x is not None, numbers) # отбрасываем мусор
print(sum(valid))
Ни одна строка не попадает в память дважды, а весь конвейер запускается только на sum().
Именно так устроена обработка данных в парсерах: страница или выгрузка приходит потоком, а не целым массивом. Написание парсеров входит в программу обучения Python в Ташкенте. Вместе с телеграм-ботами это два первых проекта, которые студенты доводят до работающего состояния.
Частые вопросы
Что возвращает map() в Python?
Объект-итератор, а не список. Чтобы получить значения, оберните результат в list(), tuple() или переберите в цикле for.
Можно ли использовать map() без lambda?
Да, и часто это предпочтительнее. Передавайте встроенную или собственную функцию по имени: map(int, data), map(str.strip, data). Для извлечения полей есть operator.itemgetter и attrgetter.
map() быстрее цикла for?
На простых преобразованиях со встроенной функцией обычно да, потому что внутренний цикл реализован на C. Если внутри lambda, разница почти исчезает.
Меняет ли map() исходный список?
Нет. Исходная последовательность остается прежней, создается новый набор значений.
Работает ли map() со словарем?
Да, но по умолчанию перебираются ключи. Для пар используйте .items(), для значений .values().
Что произойдет, если списки разной длины?
По умолчанию обработка остановится на самом коротком, без ошибки. В Python 3.14 можно передать strict=True, тогда при расхождении длин поднимется ValueError.
Чем map() отличается от filter()?
map() преобразует каждый элемент и сохраняет их количество, filter() отбирает подходящие по условию и количество уменьшает.
Как обработать ошибку внутри map()?
Встроенного механизма нет. Оберните функцию преобразования в try/except и возвращайте значение-заглушку для проблемных элементов.
Что дальше
map() — одна из первых встреч с функциональным стилем в Python. Дальше логично разобрать lambda-функции, генераторы, filter(), reduce() и модуль itertools. Вместе они закрывают большинство задач по обработке данных без единого явного цикла.
На курсе Python в PROWEB эти инструменты отрабатываются на практике: студенты пишут телеграм-ботов, парсеры и backend интернет-магазинов, где обработка коллекций встречается в каждой второй задаче. Обучение идет 8 месяцев, старт возможен с нуля.
Если пока не определились с направлением, пройдите бесплатный IT-тест, он покажет, какая сфера ближе по складу мышления.

