История вопроса
Функция enumerate() появилась в Python для удобного и идиоматичного перебора (итерации) элементов последовательности с одновременным получением текущего индекса. Это особенно важно, поскольку до этого часто рекомендовалось вручную заводить отдельный счетчик, что считалось не идеоматичным и менее читаемым.
Проблема
В циклах часто требуется знать не только текущее значение, но и его индекс в последовательности. Ручное управление индексами с помощью отдельной переменной (i) и вызова range(len(seq)) ведёт к ошибкам (расхождение индексов и значений, дублирование кода) и ухудшает читаемость.
Решение
enumerate() возвращает ленивый итератор, который на каждом шаге отдаёт кортеж (индекс, значение) текущего элемента. С помощью неё можно элегантно и надежно работать с индексами:
colors = ['red', 'green', 'blue'] for idx, color in enumerate(colors): print(idx, color)
Итерация начинается с нуля, но можно указать любое начальное значение:
for idx, color in enumerate(colors, start=1): print(idx, color)
Ключевые особенности:
enumerate() работает с любой итерируемой последовательностью, возвращает кортеж (индекс, элемент)start, что бывает удобноМожно ли отключить возвращение индекса и оставить только значения при работе с enumerate()?
Нет, enumerate() всегда возвращает пары (индекс, значение). Если требуется только значение, используйте обычный цикл for:
for value in my_list: print(value)
Можно ли использовать enumerate() с неиндексируемыми объектами, вроде генераторов?
Да, enumerate() работает с любым итерируемым объектом, включая генераторы. Индексация будет происходить по порядку появления значений:
def mygen(): for i in range(3): yield chr(ord('a')+i) for idx, val in enumerate(mygen()): print(idx, val) # 0 a, 1 b, 2 c
Можно ли автоматически задать старт индекса, отличный от 0, и что будет при отрицательных значениях?
Да, у enumerate() есть аргумент start. Если передать отрицательное значение — индексация начнётся с этого значения:
for idx, x in enumerate(['a', 'b', 'c'], start=-3): print(idx, x) # -3 a, -2 b, -1 c
range(len(seq)) вместо enumerate() для перебора списка — так код становится менее рейтинговым/идеоматичнымВ команде поддерживают большой код, часто используют:
for i in range(len(mylist)): process(i, mylist[i])
Плюсы:
Минусы:
После рефакторинга переходят на:
for idx, val in enumerate(mylist): process(idx, val)
Плюсы:
Минусы: