HOWTO · Python

Como Aceder ao Índice em Loops 'Foreach' em Python

Este artigo tutorial introduz como acessar o índice em loop foreach em Python.

Nesta página

Muitas vezes quando você está fazendo looping sobre uma coleção de itens em Python, você também precisa ter um número ordinal associado a cada item.
Tal número é normalmente referido como o index.

A forma pítonica de acessar o índice enquanto faz um loop foreach é utilizar a função embutida enumerate().

A função enumerate() adiciona um índice a cada item de uma coleção iterável.
Você então pode utilizar a função list() builtin para obter de volta uma lista de tuples.

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

Nota, a indexação Python começa a partir de 0.

Entretanto, se você quiser começar a indexar a partir de 1 (por exemplo, ao imprimir um relatório de dados), isso é trivialmente alcançado passando um argumento adicional de start para enumerate.

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

A abordagem acima também é útil se você estiver imprimindo dados de diferentes fontes de dados, mas quiser ter um índice consistente em todos os itens de dados.

>>> 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')]

Note que você não precisa converter um objeto Enumerate para uma lista.
Ele é um iterável em si, portanto pode iterar sobre ele diretamente.

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

Pode haver outras formas de obter o índice enquanto se faz a iteração sobre uma coleção de itens,
mas utilizar enumerate() é considerado canônico e é preferível.

Outra opção seria utilizar uma variável de índice separada, inicializá-la manualmente e
aumentá-la manualmente a cada iteração.
Tal abordagem, no entanto, seria considerada uma reinvenção da roda e franzida.

Aqui está uma citação de PEP 279 na qual enumerate() a função foi introduzida.

Esta PEP introduz uma nova função embutida, enumerate() para simplificar um idioma de looping comumente utilizado. Ele fornece todas as coleções iteráveis com a mesma vantagem que iteritems() oferece aos dicionários – ** uma notação de índice compacta, legível e confiável**.

Você pode perguntar se há implicações de performance ao utilizar enumerate em seu código.
Bem, você é livre para fazer todas as medidas, mas, por favor, tenha em mente que enumerate é uma maneira idiomática de acessar um índice de um iterável em um loop ‘para cada’.
O código idiomático é recomendado pelos mantenedores do Python e eles vão fazer tudo para
fazê-la funcionar eficientemente.

E para aqueles de vocês, que estão mais curiosos abaixo é uma possível implementação da função enumerate() a partir do PEP acima.

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