¿Por qué tiene que llamar a .items () al iterar sobre un diccionario en Python?

131

¿Por qué tiene que llamar items()para iterar sobre pares clave y valor en un diccionario? es decir.

dic = {'one': '1', 'two': '2'}
for k, v in dic.items():
    print(k, v)

¿Por qué no es ese el comportamiento predeterminado de iterar sobre un diccionario?

for k, v in dic:
    print(k, v)
Falmarri
fuente

Respuestas:

171

Para cada contenedor Python C, la expectativa es que

for item in C:
    assert item in C

pasará bien, ¿no le parecería sorprendente si una sensación dein (la cláusula loop) tuviera un significado completamente diferente del otro (la verificación de presencia)? ¡Seguro que lo haría! Naturalmente funciona de esa manera para listas, conjuntos, tuplas, ...

Entonces, cuando se Ctrata de un diccionario, si se inprodujeran tuplas clave / valor en un forbucle, entonces, por el principio de menor asombro, intambién tendría que tomar una tupla como su operando de la izquierda en la verificación de contención.

¿Qué tan útil sería eso? De hecho, es bastante inútil, básicamente haciendo if (key, value) in Cun sinónimo de if C.get(key) == value, que es un control que creo que podría haber realizado, o quería realizar, 100 veces más raramente de lo que if k in Crealmente significa , verificando la presencia de la clave solamente e ignorando por completo el valor.

Por otro lado, querer hacer un bucle solo en las teclas es bastante común, por ejemplo:

for k in thedict:
    thedict[k] += 1

tener el valor también no ayudaría particularmente:

for k, v in thedict.items():
    thedict[k] = v + 1

en realidad algo menos claro y menos conciso. (Tenga en cuenta que esa itemsera la ortografía original de los métodos "adecuados" para usar para obtener pares clave / valor: desafortunadamente eso fue en los días en que tales accesores devolvieron listas completas, por lo que para admitir "simplemente iterar" se tuvo que introducir una ortografía alternativa , y iteritems lo fue: en Python 3, donde las restricciones de compatibilidad con versiones anteriores de Python se debilitaron mucho, se volvió de itemsnuevo).

Alex Martelli
fuente
10

Mi suposición: usar la tupla completa sería más intuitivo para el bucle, pero tal vez menos para probar la membresía in.

if key in counts:
    counts[key] += 1
else:
    counts[key] = 1

Ese código realmente no funcionaría si tuviera que especificar tanto la clave como el valor para in. Me cuesta imaginar un caso de uso en el que verifique si tanto la clave Y el valor están en el diccionario. Es mucho más natural probar solo las claves.

# When would you ever write a condition like this?
if (key, value) in dict:

Ahora no es necesario que el inoperador y for ... inopere sobre los mismos artículos. En cuanto a la implementación, son operaciones diferentes ( __contains__vs. __iter__). Pero esa pequeña inconsistencia sería algo confusa y, bueno, inconsistente.

John Kugelman
fuente
Dado que para cualquier otro tipo de iteración incorporada que se me ocurra, x in foosolo si ien algún momento for i in fooasume el valor de x, diría que sería una gran inconsistencia.
aaronasterling