Iterando Dicionários Usando Loops 'For'
d = {'x': 1, 'y': 2, 'z': 3}
for key in d:
...
Como o Python reconhece que precisa apenas ler a chave do dicionário? Key é uma palavra especial em Python? Ou é simplesmente uma variável?
Não são apenas forloops. A palavra importante aqui é "iterando".
Um dicionário é um mapeamento de chaves para valores:
d = {'x': 1, 'y': 2, 'z': 3}
Sempre que iteramos sobre ele, iteramos sobre as chaves. O nome da variável keyé apenas para ser descritivo - e é bastante adequado para esse propósito.
Isso acontece na compreensão de uma lista:
>>> [k for k in d]
['x', 'y', 'z']
Isso acontece quando passamos o dicionário para a lista (ou qualquer outro objeto de tipo de coleção):
>>> list(d)
['x', 'y', 'z']
A maneira como o Python itera é, em um contexto em que precisa, chama o __iter__método do objeto (neste caso, o dicionário) que retorna um iterador (neste caso, um objeto keyiterator):
>>> d.__iter__()
<dict_keyiterator object at 0x7fb1747bee08>
Nós não devemos usar esses métodos especiais, em vez disso, use a respectiva função interna para chamá-la iter:
>>> key_iterator = iter(d)
>>> key_iterator
<dict_keyiterator object at 0x7fb172fa9188>
Os iteradores têm um __next__método - mas nós o chamamos com a função embutida next:
>>> next(key_iterator)
'x'
>>> next(key_iterator)
'y'
>>> next(key_iterator)
'z'
>>> next(key_iterator)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
Quando um iterador está esgotado, ele aumenta StopIteration. É assim que o Python sabe sair de um forloop, de uma compreensão de lista, de uma expressão geradora ou de qualquer outro contexto iterativo. StopIterationQuando um iterador aumenta, ele sempre será aumentado - se você quiser iterar novamente, precisará de um novo.
>>> list(key_iterator)
[]
>>> new_key_iterator = iter(d)
>>> list(new_key_iterator)
['x', 'y', 'z']
Voltando aos ditados
Já vimos ditados interagindo em muitos contextos. O que vimos é que sempre que iteramos sobre um ditado, obtemos as chaves. De volta ao exemplo original:
d = {'x': 1, 'y': 2, 'z': 3}
for key in d:
Se mudarmos o nome da variável, ainda obteremos as chaves. Vamos tentar:
>>> for each_key in d:
... print(each_key, '=>', d[each_key])
...
x => 1
y => 2
z => 3
Se queremos iterar sobre os valores, precisamos usar o .valuesmétodo dict, ou para os dois juntos .items:
>>> list(d.values())
[1, 2, 3]
>>> list(d.items())
[('x', 1), ('y', 2), ('z', 3)]
No exemplo dado, seria mais eficiente iterar sobre os itens como este:
for a_key, corresponding_value in d.items():
print(a_key, corresponding_value)
Mas, para fins acadêmicos, o exemplo da pergunta é ótimo.