Pourquoi devez-vous appeler .items () lors d'une itération sur un dictionnaire en Python?

131

Pourquoi devez-vous appeler items()pour itérer sur des paires clé / valeur dans un dictionnaire? c'est à dire.

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

Pourquoi n'est-ce pas le comportement par défaut de l'itération sur un dictionnaire

for k, v in dic:
    print(k, v)
Falmarri
la source

Réponses:

171

Pour chaque conteneur Python C, l'attente est que

for item in C:
    assert item in C

passera très bien - ne trouveriez- vous pas étonnant qu'un sens de in(la clause de boucle) ait une signification complètement différente de l'autre (le contrôle de présence)? Je le ferais sûrement! Cela fonctionne naturellement de cette façon pour les listes, les ensembles, les tuples, ...

Donc, quand Cest un dictionnaire, s'il indevait produire des tuples clé / valeur dans une forboucle, alors, par le principe du moindre étonnement, indevrait également prendre un tel tuple comme son opérande de gauche dans le contrôle de confinement.

Dans quelle mesure cela serait-il utile? Assez inutile en effet, en fait if (key, value) in Cun synonyme de if C.get(key) == value- ce qui est un contrôle que je pense avoir effectué, ou voulu effectuer, 100 fois plus rarement que ce que signifieif k in C réellement , vérifier la présence de la clé uniquement et en ignorant complètement la valeur.

D'un autre côté, vouloir boucler uniquement sur des touches est assez courant, par exemple:

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

avoir la valeur aussi n'aiderait pas particulièrement:

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

en fait un peu moins clair et moins concis. (Notez que itemsc'était l'orthographe originale des méthodes "appropriées" à utiliser pour obtenir des paires clé / valeur: malheureusement, c'était à l'époque où ces accesseurs renvoyaient des listes entières, donc pour prendre en charge "juste l'itération", une orthographe alternative a dû être introduite , et iteritems c'était - dans Python 3, où les contraintes de compatibilité ascendante avec les versions précédentes de Python étaient beaucoup affaiblies, il le redevint items).

Alex Martelli
la source
10

Je suppose: utiliser le tuple complet serait plus intuitif pour la boucle, mais peut-être moins pour tester l'appartenance à l'aide in.

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

Ce code ne fonctionnerait pas vraiment si vous deviez spécifier à la fois la clé et la valeur pour in. J'ai du mal à imaginer un cas d'utilisation où vous vérifieriez si la clé ET la valeur se trouvent dans le dictionnaire. Il est beaucoup plus naturel de tester uniquement les touches.

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

Maintenant, il n'est pas nécessaire que l' inopérateur et for ... inopèrent sur les mêmes éléments. En ce qui concerne la mise en œuvre, ce sont des opérations différentes ( __contains__vs. __iter__). Mais cette petite incohérence serait quelque peu déroutante et, enfin, incohérente.

John Kugelman
la source
Étant donné que pour tout autre type d'itérable intégré auquel je peux penser, x in fooseulement si iin for i in fooprend la valeur de xà un moment donné, je dirais que ce serait une très grande incohérence.
aaronasterling