Por que você precisa chamar .items () ao iterar sobre um dicionário em Python?

131

Por que você precisa chamar items()para iterar pares de chave e valor em um dicionário? ie

dic = {'one': '1', 'two': '2'}
for k, v in dic.items():
    print(k, v)

Por que não é esse o comportamento padrão de iterar sobre um dicionário

for k, v in dic:
    print(k, v)
Falmarri
fonte

Respostas:

171

Para cada contêiner python C, a expectativa é que

for item in C:
    assert item in C

vai passar muito bem - você não acha surpreendente se um sentido da in(a cláusula loop) tivesse um significado completamente diferente do outro (a verificação de presença)? Eu com certeza faria! Naturalmente, funciona dessa maneira para listas, conjuntos, tuplas, ...

Portanto, quando Cé um dicionário, inpara gerar tuplas de chave / valor em um forloop, então, pelo princípio de menor espanto, intambém seria necessário usar uma tupla como seu operando esquerdo na verificação de contenção.

Quão útil isso seria? Bastante inútil, na verdade, basicamente, tornando if (key, value) in Cum sinônimo para if C.get(key) == value- que é um cheque que eu acredito que pode ter realizado, ou queria fazer, 100 vezes mais raramente do que o que if k in Crealmente significa , verificando a presença da chave única e ignorando completamente o valor.

Por outro lado, querer fazer um loop apenas nas teclas é bastante comum, por exemplo:

for k in thedict:
    thedict[k] += 1

ter o valor também não ajudaria particularmente:

for k, v in thedict.items():
    thedict[k] = v + 1

na verdade, um pouco menos claro e menos conciso. (Observe que itemsera a ortografia original dos métodos "adequados" a serem usados ​​para obter pares de chave / valor: infelizmente, isso foi nos dias em que esses acessadores retornavam listas inteiras, de modo a apoiar a "iteração" uma ortografia alternativa teve que ser introduzida e iteritems foi - no Python 3, onde as restrições de compatibilidade com versões anteriores das versões anteriores do Python foram muito enfraquecidas, tornou-se itemsnovamente).

Alex Martelli
fonte
10

Meu palpite: o uso da tupla completa seria mais intuitivo para loop, mas talvez menos para testes de associação in.

if key in counts:
    counts[key] += 1
else:
    counts[key] = 1

Esse código realmente não funcionaria se você tivesse que especificar a chave e o valor in. Estou com dificuldade para imaginar um caso de uso em que você verifique se a chave E o valor estão no dicionário. É muito mais natural testar apenas as chaves.

# When would you ever write a condition like this?
if (key, value) in dict:

Agora não é necessário que o inoperador for ... inopere nos mesmos itens. Em termos de implementação, são operações diferentes ( __contains__vs. __iter__). Mas essa pouca inconsistência seria um pouco confusa e, bem, inconsistente.

John Kugelman
fonte
Dado que, para todos os outros tipos de iteráveis ​​embutidos em que consigo pensar, x in foosomente se iin for i in fooassume o valor de xem algum momento, eu diria que seria uma enorme inconsistência.
aaronasterling 19/09/10