web-dev-qa-db-fra.com

Itération sur les éléments du dictionnaire (), les valeurs (), les clés () dans Python 3

Si je comprends bien, dans Python 2, iter(d.keys()) était le même que d.iterkeys(). Mais maintenant, d.keys() est une vue , qui se situe entre la liste et l'itérateur. Quelle est la différence entre une vue et un itérateur?

En d'autres termes, en Python 3, quelle est la différence entre

for k in d.keys()
    f(k)

et

for k in iter(d.keys())
    f(k)

De plus, comment ces différences apparaissent-elles dans une simple boucle for (le cas échéant)?

40
max

Je ne suis pas sûr que ce soit une réponse à vos questions, mais j'espère que cela explique un peu la différence entre Python 2 et 3 à cet égard.

Dans Python 2, iter(d.keys()) et d.iterkeys() ne sont pas tout à fait équivalents, bien qu'ils se comportent de la même façon. Dans le premier, keys() renverra une copie de la liste des clés du dictionnaire et iter renverra alors un objet itérateur sur cette liste, avec la seconde une copie de la liste complète des clés n'est jamais construite.

Les objets de vue retournés par d.keys() dans Python 3 sont itérables (c'est-à-dire qu'un itérateur peut être fait à partir d'eux) donc quand vous dites for k in d.keys() Python créera l'itérateur pour vous. Par conséquent, vos deux exemples se comporteront de la même manière.

La signification dans le changement du type de retour pour keys() est que l'objet de vue Python 3 est dynamique. Ie si nous disons ks = d.keys() et ajoutons plus tard à d puis ks reflétera cela. Dans Python 2, keys() retourne une liste de toutes les clés actuellement dans le dict. Comparer:

Python

>>> d = { "first" : 1, "second" : 2 }
>>> ks = d.keys()
>>> ks
dict_keys(['second', 'first'])
>>> d["third"] = 3
>>> ks
dict_keys(['second', 'third', 'first'])

Python 2.x

>>> d = { "first" : 1, "second" : 2 }
>>> ks = d.keys()
>>> ks
['second', 'first']
>>> d["third"] = 3
>>> ks
['second', 'first']

As Python 3's keys() renvoie l'objet dynamique Python 3 n'a pas (et n'a pas besoin de) un iterkeys méthode.

Précision supplémentaire

Dans Python 3, keys() renvoie un objet dict_keys Mais si nous l'utilisons dans un contexte de boucle forfor k in d.keys() puis un itérateur est implicitement créé. Ainsi, la différence entre for k in d.keys() et for k in iter(d.keys()) est une création implicite vs explicite de l'itérateur.

En ce qui concerne une autre différence, bien qu'ils soient tous deux dynamiques, n'oubliez pas que si nous créons un itérateur explicite, il ne peut être utilisé qu'une seule fois alors que la vue peut être réutilisée selon les besoins. par exemple.

>>> ks = d.keys()
>>> 'first' in ks
True
>>> 'second' in ks
True
>>> i = iter(d.keys())
>>> 'first' in i
True
>>> 'second' in i
False             # because we've already reached the end of the iterator

Notez également que si nous créons un itérateur explicite puis modifions le dict, l'itérateur est invalidé:

>>> i2 = iter(d.keys())
>>> d['fourth'] = 4
>>> for k in i2: print(k)
...
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
RuntimeError: dictionary changed size during iteration

Dans Python 2, étant donné le comportement existant de keys, une méthode distincte était nécessaire pour fournir un moyen d'itérer sans copier la liste des clés tout en conservant la compatibilité descendante. Par conséquent iterkeys()

64
mikej