Qual è la differenza tra dict.items () e dict.iteritems () in Python2?


705

Ci sono differenze applicabili tra dict.items()e dict.iteritems()?

Dai documenti di Python :

dict.items(): Restituisce una copia dell'elenco di coppie (chiave, valore) del dizionario.

dict.iteritems(): Restituisce un iteratore sulle coppie (chiave, valore) del dizionario.

Se eseguo il codice qui sotto, ognuno sembra restituire un riferimento allo stesso oggetto. Ci sono delle sottili differenze che mi mancano?

#!/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'   

Produzione:

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

41
Fondamentalmente è una differenza nel modo in cui vengono calcolati. items()crea gli elementi tutti in una volta e restituisce un elenco. iteritems()restituisce un generatore - un generatore è un oggetto che "crea" un oggetto alla volta ogni volta che next()viene chiamato su di esso.
Joel Cornett,

9
Nel tuo caso particolare, d[k] is vrestituirei sempre True perché python mantiene un array di oggetti interi per tutti i numeri interi compresi tra -5 e 256: docs.python.org/2/c-api/int.html Quando crei un int in quell'intervallo, in realtà solo un riferimento all'oggetto esistente: >> a = 2; b = 2 >> a is b TrueMa,>> a = 1234567890; b = 1234567890 >> a is b False
t_tia,

3
@the_wolf Penso che sarebbe meglio aggiungere la versione Python del documento a cui ti riferisci nella domanda.
Lorenzo Belli,

2
È iteritems()cambiato iter()in Python 3? Il link della documentazione sopra non sembra corrispondere a questa risposta.
Gabriel Staples,

3
Non esattamente, @GabrielStaples. iteritems () viene rimosso dai dizionari Python 3 e non ha sostituzioni. Tuttavia, per lo stesso effetto, usi iter (). ad es. iter (dict.items ()). Vedi pep 469: python.org/dev/peps/pep-0469
Zim

Risposte:


864

Fa parte di un'evoluzione.

Inizialmente, Python ha items()creato un vero elenco di tuple e l'ha restituito. Ciò potrebbe potenzialmente richiedere molta memoria aggiuntiva.

Quindi, i generatori sono stati introdotti al linguaggio in generale e quel metodo è stato reimplementato come un metodo generatore di iteratore denominato iteritems(). L'originale rimane per compatibilità con le versioni precedenti.

Una delle modifiche di Python 3 è che items()ora restituiscono iteratori e un elenco non è mai completamente compilato. Anche il iteritems()metodo è andato, poiché items()in Python 3 funziona come viewitems()in Python 2.7.


159
Nota che hai perso un passo nell'evoluzione: il comportamento di Py3 non è lo stesso di iteritems(). In realtà crea un oggetto con protocollo di sequenza completo che riflette anche le modifiche al dict (ed è supportato dal dict stesso, piuttosto che da un elenco ridondante) - è stato riportato a 2.7 come viewitems().
PVC

3
Mi piacerebbe saperne di più in dettaglio, ma il mio google-fu mi sta fallendo. Qualcuno potrebbe indicarmi documenti, articoli o fonti che mi aiuterebbero a capirlo meglio? @lvc?
Spezzatino il

10
@Stew la modifica è descritta in PEP 3106 e c'è un po 'di più nelle novità di Python 3.0
Tadhg McDonald-Jensen,

1
Ci scusiamo per aver elaborato questa antica domanda, ma capisco correttamente che iteritems()è sempre preferibile rispettoitems() a Python 2.x?
RubenGeert,

2
@RubenGeert Il più delle volte, non importa. Per dadi molto grandi potrebbe essere preferibile.
Keith,

95

dict.items()restituisce un elenco di 2 tuple ( [(key, value), (key, value), ...]), mentre dict.iteritems()è un generatore che produce 2 tuple. Il primo richiede più spazio e tempo inizialmente, ma l'accesso a ciascun elemento è veloce, mentre il secondo richiede meno spazio e tempo inizialmente, ma un po 'più tempo nella generazione di ciascun elemento.


9
Perché ti aspetti che siano diversi?
Ignacio Vazquez-Abrams,

3
La "copia" nei documenti non significa che gli elementi vengano copiati (se lo desideri, usa copy.deepcopy). Significa che è una copia degli elementi del dizionario: se lo fai items = dct.items()e poi modifichi dctaggiungendo / eliminando le chiavi o dct[k] = other_v, itemsrimarrà lo stesso.
Dougal,

4
Nulla in Python è mai una copia approfondita se non esplicitamente documentato come tale.
Karl Knechtel,

1
@ IgnacioVazquez-Abrams - Riguardo a "più spazio e tempo": a quale dimensione del dizionario iniziano a importare. Supponiamo di avere un dizionario "grande" {1:'one', 2:'two', ... }su cui voglio scorrere su un server web e renderizzare i risultati. A quale scala dovrei iniziare a preoccuparmi di scegliere .items()vs .iteritems()per Python 2.7?
utente

1
@buffer: non sono davvero sicuro. La mia stima sarebbe di 15-20 articoli, ma non l'ho provato.
Ignacio Vazquez-Abrams,

64

In Py2.x

I comandi dict.items(), dict.keys()e dict.values()restituiscono una copia del dizionario della lista di (k, v)coppia, chiavi e valori. Ciò potrebbe richiedere molta memoria se l'elenco copiato è molto grande.

I comandi dict.iteritems(), dict.iterkeys()e dict.itervalues()restituiscono un iteratore sopra del dizionario (k, v)coppia, chiavi e valori.

I comandi dict.viewitems(), dict.viewkeys()e dict.viewvalues()restituiscono gli oggetti vista , in grado di riflettere i cambiamenti del dizionario. (Vale a dire se si inserisce delun elemento o si aggiunge una (k,v)coppia nel dizionario, l'oggetto vista può cambiare automaticamente allo stesso tempo.)

$ 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'>

Mentre in Py3.x

In Py3.x, le cose sono più puliti, dal momento che ci sono solo dict.items(), dict.keys()e dict.values()disponibile, che restituisce la vista oggetti proprio come dict.viewitems()in fatto Py2.x.

Ma

Proprio come ha notato @lvc, l' oggetto view non è lo stesso dell'iteratore , quindi se vuoi restituire un iteratore in Py3.x, puoi usare 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'>

34

Hai chiesto: "Esistono differenze applicabili tra dict.items () e dict.iteritems ()"

Questo può aiutare (per Python 2.x):

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

Puoi vedere che d.items()restituisce un elenco di tuple della chiave, coppie di valori e d.iteritems()restituisce un dizionario-itemiterator.

Come elenco, d.items () è suddivisibile:

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

Ma non avrebbe un __iter__metodo:

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

Come iteratore, d.iteritems () non è suddivisibile :

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

Ma ha __iter__:

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

Quindi gli articoli stessi sono gli stessi - il contenitore che consegna gli articoli è diverso. Uno è un elenco, l'altro un iteratore (a seconda della versione di Python ...)

Quindi le differenze applicabili tra dict.items () e dict.iteritems () sono le stesse delle differenze applicabili tra un elenco e un iteratore.


15

dict.items()restituisce un elenco di tuple e dict.iteritems()restituisce l'oggetto iteratore di tupla nel dizionario come (key,value). Le tuple sono uguali, ma il contenitore è diverso.

dict.items()fondamentalmente copia tutto il dizionario nell'elenco. Prova a utilizzare il seguente codice per confrontare i tempi di esecuzione di dict.items()e dict.iteritems(). Vedrai la differenza.

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

Uscita nella mia macchina:

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

Ciò dimostra chiaramente che dictionary.iteritems()è molto più efficiente.


4

Se hai

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

In Python 2 , dict.items()copia ogni tupla e restituisce l'elenco delle tuple nel dizionario, ad es [(key1,value1), (key2,value2), ...]. Le implicazioni sono che l'intero dizionario viene copiato in un nuovo elenco contenente tuple

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

dict.iteritems()restituisce l'iteratore dell'elemento del dizionario. Anche il valore dell'articolo restituito è lo stesso (key1,value1), (key2,value2), ..., ad esempio , ma questo non è un elenco. Questo è solo l'oggetto iteratore di voci di dizionario. Ciò significa meno utilizzo della memoria (50% in meno).

  • Elenchi come istantanee mutabili: d.items() -> list(d.items())
  • Oggetti Iteratore: d.iteritems() -> iter(d.items())

Le tuple sono uguali. Hai confrontato le tuple in ognuna per ottenere lo stesso.

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

In Python 3 , dict.items()restituisce l'oggetto iteratore. dict.iteritems () è stato rimosso, quindi non ci sono più problemi.


4

dict.iteritemsè andato in Python3.x Quindi usa iter(dict.items())per ottenere lo stesso output e memoria alocation


1

Se vuoi un modo per iterare le coppie di elementi di un dizionario che funziona con Python 2 e 3, prova qualcosa del genere:

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

Usalo in questo modo:

for key, value in DICT_ITER_ITEMS(myDict):
    # Do something with 'key' and/or 'value'.

0

dict.iteritems(): ti dà un iteratore. È possibile utilizzare l'iteratore in altri schemi al di fuori del ciclo.

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')

-5

dict.iteritems () in python 2 è equivalente a dict.items () in python 3.


2
Questo non è corretto La differenza è già stata spiegata nelle risposte precedenti.
vaultah,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.