¿Cuál es la diferencia entre dict.items () y dict.iteritems () en Python2?

705

¿Hay alguna diferencia aplicable entre dict.items()y dict.iteritems()?

De los documentos de Python :

dict.items(): Devuelve una copia de la lista de pares (clave, valor) del diccionario.

dict.iteritems(): Devuelve un iterador sobre los pares del diccionario (clave, valor).

Si ejecuto el código a continuación, cada uno parece devolver una referencia al mismo objeto. ¿Hay alguna diferencia sutil que me falta?

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

Salida:

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
el lobo
fuente
41
Básicamente es una diferencia en cómo se calculan. items()crea todos los elementos a la vez y devuelve una lista. iteritems()devuelve un generador: un generador es un objeto que "crea" un elemento a la vez cada vez que next()se lo llama.
Joel Cornett
99
En su caso particular, d[k] is vsiempre devolvería True porque python mantiene una matriz de objetos enteros para todos los enteros entre -5 y 256: docs.python.org/2/c-api/int.html Cuando crea un int en ese rango, en realidad solo >> a = 2; b = 2 >> a is b True>> a = 1234567890; b = 1234567890 >> a is b False
tengo
3
@the_wolf Creo que sería mejor agregar la versión de Python del documento al que te refieres en la pregunta.
Lorenzo Belli
2
¿Cambió iteritems()a iter()en Python 3? El enlace de documentación anterior no parece coincidir con esta respuesta.
Gabriel Staples
3
No exactamente, @GabrielStaples. iteritems () se elimina de los diccionarios Python 3 y no tiene reemplazo. Sin embargo, para el mismo efecto, usa iter (). por ejemplo, iter (dict.items ()). Ver pep 469: python.org/dev/peps/pep-0469
Zim

Respuestas:

864

Es parte de una evolución.

Originalmente, Python items()construyó una lista real de tuplas y la devolvió. Potencialmente podría tomar mucha memoria extra.

Luego, los generadores se introdujeron en el lenguaje en general, y ese método se volvió a implementar como un método iterador-generador llamado iteritems(). El original permanece por compatibilidad con versiones anteriores.

Uno de los cambios de Python 3 es que items()ahora devuelve iteradores y nunca se crea una lista completa. El iteritems()método también desapareció, ya que items()en Python 3 funciona como viewitems()en Python 2.7.

Keith
fuente
159
Tenga en cuenta que ha perdido un paso en la evolución: el comportamiento de Py3 no es el mismo que iteritems(). Realmente crea un objeto de protocolo de secuencia completa que también refleja los cambios en el dict (y está respaldado por el dict en sí mismo, en lugar de una lista redundante): se ha respaldado a 2.7 como viewitems().
lvc
3
Me gustaría aprender sobre esto en mayor detalle, pero mi google-fu me falla. ¿Podría alguien señalarme documentación, artículos o fuentes que me ayudarían a comprender esto mejor? @lvc?
Estofado
10
@Stew el cambio se describe en PEP 3106 y hay un poco más en las novedades de python 3.0
Tadhg McDonald-Jensen el
1
Perdón por profundizar en esta antigua pregunta, pero ¿entiendo correctamente que iteritems()siempre es preferibleitems() en Python 2.x?
RubenGeert
2
@RubenGeert La mayoría de las veces, no importa. Para dictados realmente grandes, podría ser preferible.
Keith
95

dict.items()devuelve una lista de 2-tuplas ( [(key, value), (key, value), ...]), mientras que dict.iteritems()es un generador que produce 2-tuplas. El primero requiere más espacio y tiempo inicialmente, pero acceder a cada elemento es rápido, mientras que el segundo requiere menos espacio y tiempo inicialmente, pero un poco más de tiempo para generar cada elemento.

Ignacio Vazquez-Abrams
fuente
99
¿Por qué esperarías que fueran diferentes?
Ignacio Vázquez-Abrams
3
La "copia" en los documentos no significa que los elementos se copien (si lo desea, use copy.deepcopy). Significa que es una copia de los elementos del diccionario: si lo hace items = dct.items()y luego modifica dctagregando / eliminando claves o dct[k] = other_v, itemspermanecerá igual.
Dougal
44
Nada en Python es nunca una copia profunda a menos que se documente explícitamente como tal.
Karl Knechtel
1
@ IgnacioVazquez-Abrams - Con respecto a "más espacio y tiempo": ¿A qué tamaño de diccionario empiezan a importar? Digamos que tengo un diccionario "grande" {1:'one', 2:'two', ... }sobre el que quiero iterar en un servidor web y mostrar los resultados. ¿A qué escala debería comenzar a preocuparme por elegir .items()vs .iteritems()para Python 2.7?
usuario
1
@buffer: No estoy muy seguro. Mi estimación sería de 15-20 artículos, pero no lo he probado.
Ignacio Vazquez-Abrams
64

En Py2.x

Los comandos dict.items(), dict.keys()y dict.values()devuelven una copia de la lista del diccionario de(k, v) pares, claves y valores. Esto podría tomar mucha memoria si la lista copiada es muy grande.

Los comandos dict.iteritems(), dict.iterkeys()y dict.itervalues()devuelven un iterador sobre el diccionario de (k, v)pares, claves y valores.

Los comandos dict.viewitems(), dict.viewkeys()y dict.viewvalues()devuelven los objetos de vista , lo que puede reflejar los cambios del diccionario. (Es decir, si usted es delun elemento o agrega un (k,v)par en el diccionario, el objeto de vista puede cambiar automáticamente al mismo tiempo).

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

Mientras que en Py3.x

En Py3.x, las cosas están más limpias, ya que solo hay dict.items() , dict.keys()y están dict.values()disponibles, que devuelven los objetos de vista tal comodict.viewitems() en Py2.x hizo.

Pero

Tal como lo señaló @lvc, ver objeto no es lo mismo que iterador , por lo que si desea devolver un iterador en Py3.x, podría usar 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
fuente
34

Usted preguntó: '¿Hay alguna diferencia aplicable entre dict.items () y dict.iteritems ()'

Esto puede ayudar (para Python 2.x):

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

Puede ver que d.items()devuelve una lista de tuplas de la clave, pares de valores yd.iteritems() devuelve un iterador de diccionario.

Como lista, d.items () es divisible:

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

Pero no tendría un __iter__método:

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

Como iterador, d.iteritems () no es divisible :

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

Pero tiene __iter__:

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

Por lo tanto, los artículos en sí son los mismos: el contenedor que entrega los artículos es diferente. Uno es una lista, el otro un iterador (dependiendo de la versión de Python ...)

Entonces, las diferencias aplicables entre dict.items () y dict.iteritems () son las mismas que las diferencias aplicables entre una lista y un iterador.

perro
fuente
15

dict.items()devolver la lista de tuplas y dict.iteritems()devolver el objeto iterador de tupla en el diccionario como (key,value). Las tuplas son iguales, pero el contenedor es diferente.

dict.items()básicamente copia todo el diccionario en la lista. Intente usar el siguiente código para comparar los tiempos de ejecución de dict.items()y dict.iteritems(). Verás la diferencia.

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

Salida en mi máquina:

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

Esto muestra claramente que dictionary.iteritems()es mucho más eficiente.

Prabhu
fuente
4

Si usted tiene

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

En Python 2 , dict.items()copia cada tupla y devuelve la lista de tuplas en el diccionario, es decir [(key1,value1), (key2,value2), ...]. Las implicaciones son que todo el diccionario se copia a una nueva lista que contiene tuplas

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

dict.iteritems()devuelve el iterador del elemento del diccionario. El valor del artículo devuelto también es el mismo (key1,value1), (key2,value2), ..., es decir , pero esto no es una lista. Este es solo un objeto iterador del elemento del diccionario. Eso significa menos uso de memoria (50% menos).

  • Listas como instantáneas mutables: d.items() -> list(d.items())
  • Objetos iteradores: d.iteritems() -> iter(d.items())

Las tuplas son iguales. Comparaste tuplas en cada una para obtener lo mismo.

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()devuelve el objeto iterador. dict.iteritems () se elimina para que no haya más problemas.

Hary Bakta
fuente
4

dict.iteritemsdesapareció en Python3.x Así que úselo iter(dict.items())para obtener la misma salida y ubicación

Tessaracter
fuente
1

Si desea una forma de iterar los pares de elementos de un diccionario que funciona con Python 2 y 3, intente algo como esto:

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

Úselo así:

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

dict.iteritems(): te da un iterador. Puede usar el iterador en otros patrones fuera 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')
etplumber
fuente
-5

dict.iteritems () en python 2 es equivalente a dict.items () en python 3.

usuario128364
fuente
2
Esto es incorrecto. La diferencia ya se ha explicado en respuestas anteriores.
vaultah