Как получить доступ к индексу в Foreach петлях на Python

Часто, когда вы перебираете коллекцию предметов на Python, вам также необходимо иметь порядковый номер, связанный с каждым предметом. Такой номер обычно называется индексом.

Pythonический способ доступа к индексу при выполнении форач-петли заключается в использовании встроенной функции enumerate().

enumerate() добавляет индекс к каждому элементу в итерабельной коллекции. Затем вы можете использовать встроенную функцию list() для получения списка кортежей.

>>> names = ['Bob', 'Alice', 'John', 'Cindy']
>>> list(enumerate(names))
[(0, 'Bob'), (1, 'Alice'), (2, 'John'), (3, 'Cindy')]

Обратите внимание, Python индексирование начинается с 0.

Однако, если вы хотите начать индексацию с 1 (например, при печати данных отчёта), это тривиально достигается передачей дополнительного аргумента start в enumerate.

>>> names = ['Bob', 'Alice', 'John', 'Cindy']
>>> list(enumerate(names), start=1)
[(1, 'Bob'), (2, 'Alice'), (3, 'John'), (4, 'Cindy')]

Вышеприведенный подход также полезен, если Вы печатаете данные из разных источников данных, но хотите иметь последовательный индекс по всем элементам данных.

>>> data_source1 = ['Bob', 'Alice', 'John', 'Cindy']
>>> data_source2 = ['Sarah', 'Jeff', 'Emily', 'Adam']
>>> list(enumerate(data_source1, start=1))
[(1, 'Bob'), (2, 'Alice'), (3, 'John'), (4, 'Cindy')]
>>> list(enumerate(data_source2, start=len(data_source1) + 1))
[(5, 'Sarah'), (6, 'Jeff'), (7, 'Emily'), (8, 'Adam')]

Обратите внимание, что вам не нужно преобразовывать объект Enumerate в список. Он сам по себе является итерабельным, поэтому может выполнять прямые итерации.

>>> names = ['Bob', 'Alice', 'John', 'Cindy']
>>> for idx, name in enumerate(names):
...   print(name)
...
Bob
Alice
John
Cindy

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

Другой вариант - использовать отдельную переменную индекса, инициализировать ее вручную и увеличивать вручную на каждой итерации. Однако такой подход будет расцениваться как повторное изобретение колеса и на него будут нахмуриться.

Вот цитата из PEP 279, в которой была введена функция enumerate().

Эта PEP представляет новую встроенную функцию, enumerate() для упрощения обычно используемой идиомы петлирования. Она предоставляет все итерабельные коллекции с тем же преимуществом, которое функция iteritems() дает словарям – ** компактная, читаемая, надежная индексная нотация**.

Вы можете спросить, есть ли какие-нибудь последствия для производительности при использовании enumerate в вашем коде. Ну, вы вольны делать все измерения, но, пожалуйста, имейте в виду, что enumerate является идиоматическим способом доступа к индексу итерабельного в “для каждого” цикла. Идиоматический код рекомендуется мейнтейнерами Python, и они сделают всё, чтобы заставить его работать эффективно.

А для тех из вас, кому любопытнее всего ниже, возможна реализация функции enumerate() от вышестоящей PEP.

def enumerate(collection):
   'Generates an indexed series:  (0,coll[0]), (1,coll[1]) ...'
   i = 0
   it = iter(collection)
   while 1:
       yield (i, it.next())
       i += 1
comments powered by Disqus