Python enumerate для пар индекс и значение
Python enumerate добавляет бегущий индекс к итерируемому объекту и возвращает пары (индекс, значение) при обходе.
Используйте его, когда нужна позиция каждого элемента, например для нумерованного вывода или меток.
Это встроенный паттерн для связывания элемента с его позицией в списках, генераторах или строках файла.
Пример Python Enumerate Для Нумерованного Вывода
Вывод:
Результат появится здесь...
Вывод:
1. отправить заказ
2. написать клиенту
Как Работает Этот Пример
enumerate(tasks, start=1)связывает каждую задачу с её позицией.start=1делает номера человекочитаемыми.- Вывод показывает каждую задачу с номером.
Частые ошибки с Python enumerate
Ошибка 1: Забыть, что нумерация начинается с 0.
for line_no, row in enumerate(rows):
print(f"Строка {line_no}: {row['sku']}")
for line_no, row in enumerate(rows, start=1):
print(f"Строка {line_no}: {row['sku']}")
Почему это происходит: enumerate по умолчанию стартует с 0, что корректно для индексов, но сбивает в пользовательских номерах строк.
Ошибка 2: Перебирать словарь и ожидать значения.
region_totals = {"запад": 1200, "восток": 980}
for i, total in enumerate(region_totals):
print(i, total)
region_totals = {"запад": 1200, "восток": 980}
for i, (region, total) in enumerate(region_totals.items(), start=1):
print(i, region, total)
Почему это происходит: при итерации по dict возвращаются ключи, поэтому enumerate связывает индекс с ключом, если не использовать .items().
Если нужен паттерн ключ/значение, см. пример Python dict.
Ошибка 3: Делать list(enumerate(...)) для больших данных.
indexed_rows = list(enumerate(rows, start=1))
for line_no, row in indexed_rows:
print(line_no, row)
for line_no, row in enumerate(rows, start=1):
print(line_no, row)
Почему это происходит: list() загружает все пары в память, тогда как enumerate и так ленивый и может стримить.
enumerate vs range(len()): что использовать
Используйте enumerate, когда… | Используйте range(len()), когда… |
|---|---|
| Нужны и индекс, и элемент вместе. | Нужны только числовые индексы. |
| Вы итерируете любой объект, включая генераторы. | Нужно ходить с кастомным шагом или только по индексам. |
| Хотите читабельные циклы без ручной индексации. | Работаете с индексами для срезов или случайного доступа. |
Правило: выбирайте enumerate для индекса + значения; range(len()) — когда нужен сам индекс.
Если нужны только вычисления с индексами, см. пример Python range.
Соображения По Производительности
enumerate — это O(n) и ленивость, поэтому он не создаёт лишний список пар, если вы не оборачиваете его в list(). На практике он быстрее и понятнее, чем вызов list.index() внутри цикла (что делает цикл O(n^2)). Если вам нужно только пронумеровать строки, enumerate сохраняет постоянную память и даёт номера строк.
Другие случаи использования enumerate
Отмечать строки с ошибками при анализе логов.
lines = [
"INFO подключено",
"ОШИБКА таймаут",
"INFO повтор",
]
for line_no, line in enumerate(lines, start=1):
if "ОШИБКА" in line:
print(f"Строка {line_no}: {line}")
Это оставляет точный номер строки рядом с каждой ошибкой, ускоряя отладку и разбор инцидентов.
Так же работает и для файлов, потому что enumerate принимает любой итерируемый объект.
Нормализовать список на месте по индексу.
names = [" ada", "grace ", " linus"]
for i, name in enumerate(names):
# обновляем по индексу, когда нужно мутировать список на месте
names[i] = name.strip().title()
print(names)
Это оставляет данные в том же списке и даёт индекс для обратного присваивания. Так понятнее, чем вести ручной счётчик, и цикл остаётся читаемым.