2012-05-02 16 views
8

¿Existe alguna manera de iterar de manera eficiente sobre los valores/elementos en un diccionario que funciona tanto en Python 2 como en Python 3?Generadores para iterar uniformemente en un diccionario tanto en Python 2 como en 3

En Python 2, puedo escribir

for x in mydict: 
for x in mydict.iterkeys(): 
for x in mydict.viewkeys(): 
for x in mydict.itervalues(): 
for x in mydict.viewvalues(): 
for x in mydict.iteritems(): 
for x in mydict.viewitems(): 

y en Python 3, tengo las siguientes posibilidades:

for x in mydict: 
for x in mydict.keys(): 
for x in mydict.values(): 
for x in mydict.items(): 

lo tanto, puedo iterar sobre las claves con for x in mydict, y que las obras tanto en Python 2 como en 3. Pero, ¿hay alguna forma de iterar sobre valores y pares clave-valor ('elementos') que funcione universalmente? Lo necesito para escribir el código de Python que se puede ejecutar en ambas versiones de Python.

(En una nota lateral, otros obstáculos con los iteradores se pueden omitir fácilmente; tomar, por ejemplo:

if sys.version_info.major<3: 
    from itertools import izip as zip, imap as map 

Sin embargo, los métodos de diccionario no pueden ser redefinidos fácilmente como map y zip.)

Cualquier ideas?

+1

EDIT: Creo que quieres decir que los generadores iteran sobre el diccionario – jamylak

+0

@jamylak: sí, gracias. – Daniel

Respuesta

9

valores() versión de Sólo otro burro de responder

for value in (mydict[key] for key in mydict): 

o

def dict_values(d): 
    return (mydict[key] for key in mydict) 

def dict_items(d): 
    return ((key, mydict[key]) for key in mydict) 

for value in dict_values(mydict): 
    ... 

for value in dict_items(mydict): 
    ... 

Esto es bastante malo. Se puede comprobar la versión de Python y en lugar de devolver el generador, volver d.items() o d.iteritems() según corresponda

creo que una mejor pregunta puede ser la forma de escribir código python2 que funciona bien con 2to3 y genera código de buena python3

+4

+1 para la última frase. – Daenyth

+0

Favorezco la propuesta de gnibbler de comprobar la versión de Python (una vez, al comienzo de la secuencia de comandos de Python) y definir las funciones que devuelven el iterador correcto 'd.items()' o 'd.iteritems()'. – Daniel

0

Python2.7 tiene un método .items en el diccionario que le permite iterar sobre tuplas (clave, valor). Python3 tiene la misma API (aunque la implementación es diferente). Funcionara para ti?

+0

pero en Python2, '.items()' crea una lista temporal que el OP intenta evitar –

+0

La pregunta no es muy clara, pero creo que el autor quiere generadores. Cambié el título de la pregunta para reflejar eso. – jamylak

+0

No me di cuenta de eso. Gracias. –

3

Esto le dará un generador:

for key,value in ((key,mydict[key] for key in mydict) 

Si desea una lista, utilice [] alrededor de la expresión en lugar de la() en el exterior

+1

Una manera más fácil sería usar mydict.iteritems() –

+0

Lo que tienes en la publicación funcionaría tanto en 2 como en 3, pero '.iteritems() 'no existe en 3. Al menos no con ese nombre, se renombró a' .items() '. –

+0

Podrías simplemente usar la solución anterior. Prefiero alejarme de las listas porque si el tamaño del diccionario es demasiado grande, creo que hacer una nueva lista crea una lista grande. –

7

El siguiente código funciona tanto en Py2 y AP3:

def iteritems(d): 
    'Factor-out Py2-to-3 differences in dictionary item iterator methods' 
    try: 
     return d.iteritems() 
    except AttributeError: 
     return d.items() 

d = dict(red=1, blue=2, green=3) 
for k, v in iteritems(d): 
    print(k) 
    print(v) 
    print('') 

Nota, esta solución tiene la ventaja de utilizar los iteradores nativos en lugar de rodar sus propios generadores y hacer sus propias búsquedas. Los iteradores nativos son más rápidos que las otras soluciones presentadas.

Cuestiones relacionadas