Шаг 71.
Python: сборник рецептов. Итераторы и генераторы. Итерирование по парам "индекс-значение" последовательности

    На этом шаге мы рассмотрим использование функции enumerate().

Задача

    Вы хотите проитерировать по последовательности и при этом хранить информацию о том, какой по счету элемент сейчас обрабатывается.

Решение

    Встроенная функция enumerate() изящно справляется с этой задачей:

>>> my_list = ['a', 'b', 'c']
>>> for idx, val in enumerate(my_list):
	print(idx, val)

	
0 a
1 b
2 c

    Для печати вывода с привычными номерами строк (то есть с нумерацией, начинающейся с 1, а не с 0) вы можете передать соответствующий аргумент start:

>>> my_list = ['a', 'b', 'c']
>>> for idx, val in enumerate(my_list, 1):
	print(idx, val)

	
1 a
2 b
3 c
>>> 

    Этот прием особенно полезен для учета номеров строк в файлах, если нужно будет вывести номер строки в сообщении об ошибке:

def parse_data(filename):
    with open(filename, 'rt') as f:
        for lineno, line in enumerate(f, 1):
            fields = line.split()
            try:
                count = int(fields[1])
                 ...
            except ValueError as e:
                print('Line {}: Parse error: {}'.format(lineno, e))

    Функция enumerate() удобна, например, для отслеживания смещения (offset) в списке для вхождений определенных значений. Так что если вы хотите отобразить слова в файле к строкам, в которых они встречаются, это легко сделать с помощью enumerate() - функция отображает каждое слово на смещение строки в файле, где оно найдено:

word_summary = defaultdict(list)

with open('myfile.txt', 'r') as f: 
    lines = f.readlines()

for idx, line in enumerate(lines):
    #  Создает список слов в текущей строке
    words = [w.strip().lower() for w in line.split()] 
    for word in words:
        word_summary[word].append(idx)

    Если вы выведете word_summary после обработки файла, это будет словарь (default dict, если быть точными), и каждое слово будет ключом. Значение каждого ключа - список номеров строк, где встретилось это слово. Если слово встретилось дважды в одной строке, этот номер строки будет записан в список дважды, что делает возможным получение разнообразных простых метрик текста.

Обсуждение

    enumerate() - симпатичное решение для ситуаций, где вы могли бы склоняться к использованию собственной переменной-счетчика. Вы могли бы написать такой код:

lineno = 1
for line in f:
    #  Обработка строки
    .   .   .   .
    lineno += 1

    Но часто более элегантным (и менее подверженным ошибкам) способом становится использование enumerate():

for lineno, line in enumerate(f):
    # Обработка строки
    .   .   .   .

    Значение, возвращаемое функцией enumerate(), является объектом enumerate. Это итератор, который последовательно возвращает кортежи, состоящие из счетчика и значения, возвращаемого вызовом функции next() для последовательности, которую вы обходите.

    Стоит отметить, что иногда можно запутаться при применении enumerate() к последовательности кортежей, которые при этом распаковываются:

data = [(1, 2), (3, 4), (5, 6), (7, 8)]
# Верно!
for n, (x, y) in enumerate(data):
    .   .   .   .
# Ошибка!
for n, x, y in enumerate(data):
    .   .   .   .

    На следующем шаге мы рассмотрим одновременное итерирование по нескольким последовательностям.




Предыдущий шаг Содержание Следующий шаг