Quelle est la différence entre dict.items () et dict.iteritems () en Python2?

705

Existe-t-il des différences applicables entre dict.items()et dict.iteritems()?

Depuis les documents Python :

dict.items(): Renvoie une copie de la liste des paires (clé, valeur) du dictionnaire.

dict.iteritems(): Retourne un itérateur sur les paires (clé, valeur) du dictionnaire.

Si j'exécute le code ci-dessous, chacun semble renvoyer une référence au même objet. Y a-t-il des différences subtiles qui me manquent?

#!/usr/bin/python

d={1:'one',2:'two',3:'three'}
print 'd.items():'
for k,v in d.items():
   if d[k] is v: print '\tthey are the same object' 
   else: print '\tthey are different'

print 'd.iteritems():'   
for k,v in d.iteritems():
   if d[k] is v: print '\tthey are the same object' 
   else: print '\tthey are different'   

Production:

d.items():
    they are the same object
    they are the same object
    they are the same object
d.iteritems():
    they are the same object
    they are the same object
    they are the same object
le loup
la source
41
C'est fondamentalement une différence dans la façon dont ils sont calculés. items()crée les éléments en une seule fois et renvoie une liste. iteritems()renvoie un générateur - un générateur est un objet qui "crée" un élément à la fois chaque fois qu'il next()est appelé dessus.
Joel Cornett
9
Dans votre cas particulier, d[k] is vretournerait toujours True car python conserve un tableau d'objets entiers pour tous les entiers compris entre -5 et 256: docs.python.org/2/c-api/int.html Lorsque vous créez un int dans cette plage, vous en fait juste récupérer une référence à l'objet existant: >> a = 2; b = 2 >> a is b TrueMais,>> a = 1234567890; b = 1234567890 >> a is b False
t_tia
3
@the_wolf Je pense qu'il serait préférable d'ajouter la version python du document auquel vous faites référence dans la question.
Lorenzo Belli
2
Avez-vous iteritems()changé iter()en Python 3? Le lien de documentation ci-dessus ne semble pas correspondre à cette réponse.
Gabriel Staples le
3
Pas exactement, @GabrielStaples. iteritems () est supprimé des dictionnaires Python 3 et n'a pas de remplacement. Cependant, pour le même effet, vous utilisez iter (). par exemple iter (dict.items ()). Voir pep 469: python.org/dev/peps/pep-0469
Zim

Réponses:

864

Cela fait partie d'une évolution.

À l'origine, Python a items()construit une véritable liste de tuples et l'a renvoyée. Cela pourrait potentiellement prendre beaucoup de mémoire supplémentaire.

Ensuite, les générateurs ont été introduits dans le langage en général, et cette méthode a été réimplémentée en tant que méthode itérateur-générateur nommée iteritems(). L'original reste pour une compatibilité descendante.

L'une des modifications de Python 3 est que items()maintenant les itérateurs de retour, et une liste n'est jamais entièrement construite. La iteritems()méthode a également disparu, car items()en Python 3 fonctionne comme viewitems()en Python 2.7.

Keith
la source
159
Notez que vous avez raté une étape de l'évolution: le comportement de Py3 n'est pas le même que iteritems(). Il crée en fait un objet de protocole de séquence complet qui reflète également les modifications apportées au dict (et est soutenu par le dict lui-même, plutôt que par une liste redondante) - il a été rétroporté vers 2.7 as viewitems().
lvc
3
Je voudrais en savoir plus à ce sujet, mais mon google-fu me fait défaut. Quelqu'un pourrait-il m'indiquer de la documentation, des articles ou une source qui pourraient m'aider à mieux comprendre cela? @lvc?
Ragoût
10
@Stew le changement est décrit dans PEP 3106 et il y a un peu plus dans les nouveautés de python 3.0
Tadhg McDonald-Jensen
1
Désolé d'avoir développé cette ancienne question, mais ai-je bien compris que iteritems()c'est toujours préférableitems() à Python 2.x?
RubenGeert
2
@RubenGeert La plupart du temps, cela n'a pas d'importance. Pour les très gros dits, cela pourrait être préférable.
Keith
95

dict.items()renvoie une liste de 2-tuples ( [(key, value), (key, value), ...]), alors que dict.iteritems()est un générateur qui donne 2-tuples. Le premier prend plus d'espace et de temps au départ, mais l'accès à chaque élément est rapide, tandis que le second prend moins d'espace et de temps au départ, mais un peu plus de temps pour générer chaque élément.

Ignacio Vazquez-Abrams
la source
9
Pourquoi vous attendriez-vous à ce qu'ils soient différents?
Ignacio Vazquez-Abrams
3
La "copie" dans les documents ne signifie pas que les éléments sont copiés (si vous le souhaitez, utilisez copy.deepcopy). Cela signifie qu'il s'agit d'une copie des éléments du dictionnaire: si vous le faites items = dct.items()puis modifiez dcten ajoutant / supprimant des clés ou dct[k] = other_v, itemscela restera le même.
Dougal
4
Rien dans Python n'est jamais une copie complète à moins qu'il ne soit explicitement documenté comme tel.
Karl Knechtel
1
@ IgnacioVazquez-Abrams - Concernant "plus d'espace et de temps": à quelle taille de dictionnaire commencent-ils à avoir de l'importance. Disons que j'ai un "grand" dictionnaire {1:'one', 2:'two', ... }sur lequel je veux itérer sur un serveur Web et rendre les résultats. À quelle échelle devrais-je commencer à me soucier de choisir .items()vs .iteritems()pour Python 2.7?
utilisateur
1
@buffer: Pas vraiment sûr. Mon estimation serait de 15 à 20 articles, mais je ne l'ai pas testé.
Ignacio Vazquez-Abrams
64

Dans Py2.x

Les commandes dict.items(), dict.keys()et dict.values()renvoient une copie du dictionnaire du Liste des (k, v)paires, des clés et des valeurs. Cela peut prendre beaucoup de mémoire si la liste copiée est très volumineuse.

Les commandes dict.iteritems(), dict.iterkeys()et dict.itervalues()renvoient un itérateur sur le dictionnaire (k, v)paire, les clés et les valeurs.

Les commandes dict.viewitems(), dict.viewkeys()et dict.viewvalues()renvoient les objets de vue , ce qui peut refléter les changements du dictionnaire. (C'est-à-dire si vous delun élément ou ajoutez une (k,v)paire dans le dictionnaire, l'objet de vue peut changer automatiquement en même temps.)

$ python2.7

>>> d = {'one':1, 'two':2}
>>> type(d.items())
<type 'list'>
>>> type(d.keys())
<type 'list'>
>>> 
>>> 
>>> type(d.iteritems())
<type 'dictionary-itemiterator'>
>>> type(d.iterkeys())
<type 'dictionary-keyiterator'>
>>> 
>>> 
>>> type(d.viewitems())
<type 'dict_items'>
>>> type(d.viewkeys())
<type 'dict_keys'>

En Py3.x

Dans Py3.x, les choses sont plus propres, car il y en a seulement dict.items(), dict.keys()et dict.values()disponibles, qui retournent les objets de vue comme dict.viewitems()dans Py2.x.

Mais

Tout comme @lvc l'a noté, l' objet de vue n'est pas le même que l' itérateur , donc si vous voulez retourner un itérateur dans Py3.x, vous pouvez utiliser 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
34

Vous avez demandé: «Existe-t-il des différences applicables entre dict.items () et dict.iteritems ()»

Cela peut aider (pour Python 2.x):

>>> d={1:'one',2:'two',3:'three'}
>>> type(d.items())
<type 'list'>
>>> type(d.iteritems())
<type 'dictionary-itemiterator'>

Vous pouvez voir que d.items()renvoie une liste de tuples de la clé, les paires de valeurs et d.iteritems()renvoie un dictionnaire-itemiterator.

En tant que liste, d.items () est découpable:

>>> l1=d.items()[0]
>>> l1
(1, 'one')   # an unordered value!

Mais n'aurait pas de __iter__méthode:

>>> next(d.items())
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: list object is not an iterator

En tant qu'itérateur, d.iteritems () n'est pas découpable :

>>> i1=d.iteritems()[0]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'dictionary-itemiterator' object is not subscriptable

Mais a __iter__:

>>> next(d.iteritems())
(1, 'one')               # an unordered value!

Les articles eux-mêmes sont donc les mêmes - le conteneur qui livre les articles est différent. L'un est une liste, l'autre un itérateur (selon la version Python ...)

Ainsi, les différences applicables entre dict.items () et dict.iteritems () sont les mêmes que les différences applicables entre une liste et un itérateur.

dawg
la source
15

dict.items()retourne la liste des tuples et dict.iteritems()retourne l'objet itérateur du tuple dans le dictionnaire comme (key,value). Les tuples sont les mêmes, mais le conteneur est différent.

dict.items()copie essentiellement tout le dictionnaire dans la liste. Essayez d'utiliser le code suivant pour comparer les temps d'exécution de dict.items()et dict.iteritems(). Vous verrez la différence.

import timeit

d = {i:i*2 for i in xrange(10000000)}  
start = timeit.default_timer() #more memory intensive
for key,value in d.items():
    tmp = key + value #do something like print
t1 = timeit.default_timer() - start

start = timeit.default_timer()
for key,value in d.iteritems(): #less memory intensive
    tmp = key + value
t2 = timeit.default_timer() - start

Sortie dans ma machine:

Time with d.items(): 9.04773592949
Time with d.iteritems(): 2.17707300186

Cela montre clairement que dictionary.iteritems()c'est beaucoup plus efficace.

Prabhu
la source
4

Si tu as

dict = {key1:value1, key2:value2, key3:value3,...}

En Python 2 , dict.items()copie chaque tuples et retourne la liste des tuples dans le dictionnaire ie [(key1,value1), (key2,value2), ...]. Les implications sont que le dictionnaire entier est copié dans une nouvelle liste contenant des tuples

dict = {i: i * 2 for i in xrange(10000000)}  
# Slow and memory hungry.
for key, value in dict.items():
    print(key,":",value)

dict.iteritems()renvoie l'itérateur d'élément de dictionnaire. La valeur de l'article retourné est également la même c'est (key1,value1), (key2,value2), ...-à- dire , mais ce n'est pas une liste. Il s'agit uniquement d'un objet itérateur d'élément de dictionnaire. Cela signifie moins d'utilisation de la mémoire (50% de moins).

  • Listes sous forme d'instantanés mutables: d.items() -> list(d.items())
  • Objets itérateur: d.iteritems() -> iter(d.items())

Les tuples sont les mêmes. Vous avez comparé les tuples dans chacun afin d'obtenir la même chose.

dict = {i: i * 2 for i in xrange(10000000)}  
# More memory efficient.
for key, value in dict.iteritems():
    print(key,":",value)

En Python 3 , dict.items()retourne un objet itérateur. dict.iteritems () est supprimé afin qu'il n'y ait plus de problème.

Hary Bakta
la source
4

dict.iteritemsest parti en Python3.x Donc, utilisez iter(dict.items())pour obtenir la même allocation de sortie et de mémoire

Tessaracter
la source
1

Si vous voulez un moyen d'itérer les paires d'éléments d'un dictionnaire qui fonctionne avec Python 2 et 3, essayez quelque chose comme ceci:

DICT_ITER_ITEMS = (lambda d: d.iteritems()) if hasattr(dict, 'iteritems') else (lambda d: iter(d.items()))

Utilisez-le comme ceci:

for key, value in DICT_ITER_ITEMS(myDict):
    # Do something with 'key' and/or 'value'.
R. Navega
la source
0

dict.iteritems(): vous donne un itérateur. Vous pouvez utiliser l'itérateur dans d'autres modèles en dehors de la boucle.

student = {"name": "Daniel", "student_id": 2222}

for key,value in student.items():
    print(key,value)

('student_id', 2222)
('name', 'Daniel')

for key,value in student.iteritems():
    print(key,value)

('student_id', 2222)
('name', 'Daniel')

studentIterator = student.iteritems()

print(studentIterator.next())
('student_id', 2222)

print(studentIterator.next())
('name', 'Daniel')
ethplumber
la source
-5

dict.iteritems () en python 2 est équivalent à dict.items () en python 3.

user128364
la source
2
Ceci est une erreur. La différence a déjà été expliquée dans les réponses précédentes.
vaultah