Quand faut-il utiliser iteritems () à la place de items ()?

153

Est-il légitime d'utiliser items()au lieu de iteritems()partout? Pourquoi a été iteritems()supprimé de Python 3? Cela semble être une méthode formidable et utile. Quel est le raisonnement derrière cela?

Edit: Pour clarifier, je veux savoir quel est l'idiome correct pour itérer sur un dictionnaire à la manière d'un générateur (un élément à la fois, pas tout en mémoire) d'une manière compatible avec Python 2 et Python 3 ?

Martineau
la source

Réponses:

148

En Python 2.x - a .items()renvoyé une liste de paires (clé, valeur). En Python 3.x, .items()est maintenant un itemviewobjet, qui se comporte différemment - il doit donc être itéré ou matérialisé ... Donc, list(dict.items())est requis pour ce qui était dict.items()dans Python 2.x.

Python 2.7 a également un peu de back-port pour la gestion des clés, en ce que vous avez viewkeys, viewitemset des viewvaluesméthodes, le plus utile étant viewkeysqui se comporte plus comme a set(ce que vous attendez de a dict).

Exemple simple:

common_keys = list(dict_a.viewkeys() & dict_b.viewkeys())

Vous donnera une liste des clés communes, mais encore une fois, dans Python 3.x - utilisez simplement à la .keys()place.

Python 3.x a généralement été conçu pour être plus «paresseux» - c'est-à-dire qu'il mapest maintenant effectivement itertools.imap, zipest itertools.izip, etc.

Jon Clements
la source
96

dict.iteritemsa été supprimé car fait dict.itemsmaintenant la chose dict.iteritemsfaite en python 2.x et l'a même amélioré un peu en en faisant un itemview.

Wessie
la source
64

La bibliothèque six aide à écrire du code compatible avec python 2.5+ et python 3. Elle a une méthode iteritems qui fonctionnera à la fois en python 2 et 3. Exemple:

import six

d = dict( foo=1, bar=2 )

for k, v in six.iteritems(d):
    print(k, v)
Dean Serenevy
la source
9

Comme vous le dirait la documentation du dictionnaire pour python 2 et python 3 , en python 2 itemsrenvoie une liste, tandis que iteritemsrenvoie un itérateur.

En python 3, itemsrenvoie une vue , qui est à peu près la même qu'un itérateur.

Si vous utilisez python 2, vous voudrez peut-être utiliser iteritemssi vous avez affaire à de gros dictionnaires et que tout ce que vous voulez faire est de parcourir les éléments (pas nécessairement de les copier dans une liste)

Goncalopp
la source
Je comprends que iteritemsc'est un itérateur, c'est pourquoi c'est si utile. Je ne veux presque jamais parcourir un dictionnaire sous forme de liste. Alors, quelle est la bonne façon d'itérer sur le dictionnaire avec quelque chose de générateur comme d'une manière compatible avec Python 2 et 3?
3
@ user248237 for key in some_dictfonctionne sur les deux - et l' 2to3outil se traduira iteritems()de items()toute façon ...
Jon Clements
1
@JonClements: assez juste, même si j'ai toujours pensé que for k in d: d[k]c'était inutilement verbeux / impythonique
6

Tout comme @Wessie a noté dict.iteritems, dict.iterkeyset dict.itervalues(qui renvoient un itérateur en python2.X), ainsi que dict.viewitems, dict.viewkeyset dict.viewvalues(qui retour vue des objets dans python2.X) ont tous été retirés dans Python3.x

Et dict.items, dict.keyset dict.valuesutilisé pour renvoyer une copie de la liste du dictionnaire dans Python2.x renvoie maintenant des objets de vue dans Python3.x, mais ils ne sont toujours pas les mêmes que l' itérateur .

Si vous souhaitez renvoyer un itérateur dans Python3.x, utilisez iter(dictview):

$ python3.3

>>> d = {'one':'1', 'two':'2'}
>>> type(d.items())
<class 'dict_items'>
>>>
>>> type(d.keys())
<class 'dict_keys'>
>>>
>>>
>>> ii = iter(d.items())
>>> type(ii)
<class 'dict_itemiterator'>
>>>
>>> ik = iter(d.keys())
>>> type(ik)
<class 'dict_keyiterator'>
YaOzI
la source
Qu'est-ce qui est le plus efficace quand on veut faire une recherche inverse? afficher des objets ou un itérateur?
lifebalance
6

Vous ne pouvez pas utiliser à la itemsplace iteritemsdans tous les endroits en Python. Par exemple, le code suivant:

class C:
  def __init__(self, a):
    self.a = a
  def __iter__(self):
    return self.a.iteritems()

>>> c = C(dict(a=1, b=2, c=3))
>>> [v for v in c]
[('a', 1), ('c', 3), ('b', 2)]

se cassera si vous utilisez items:

class D:
  def __init__(self, a):
    self.a = a
  def __iter__(self):
    return self.a.items()

>>> d = D(dict(a=1, b=2, c=3))
>>> [v for v in d]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: __iter__ returned non-iterator of type 'list'

Il en va de même pour viewitems , qui est disponible dans Python 3.

De plus, comme items renvoie une copie de la liste des (key, value)paires du dictionnaire , il est moins efficace, à moins que vous ne souhaitiez quand même créer une copie.

Dans Python 2, il est préférable d'utiliser iteritemspour l'itération. L' 2to3outil peut le remplacer par itemssi vous décidez de passer à Python 3.

Florian hiver
la source
0

future.utils permet la compatibilité avec Python 2 et 3

# Python 2 and 3: option 3
from future.utils import iteritems
heights = {'man': 185,'lady': 165}
for (key, value) in iteritems(heights):
    print(key,value)

>>> ('lady', 165)
>>> ('man', 185)

https://python-future.org/compatible_idioms.html

Daniel
la source