2008-12-04 13 views
12

dict methods dict.keys(), dict.items() y dict.values ​​() devuelven "vistas" en lugar de listas. http://docs.python.org/dev/3.0/whatsnew//3.0.htmlPython 3.0 - los métodos dict devuelven vistas - ¿por qué?

En primer lugar, ¿cómo es una vista diferente de un iterador? En segundo lugar, ¿cuál es el beneficio de este cambio? ¿Es solo por razones de rendimiento?

No me parece intuitivo, es decir, estoy pidiendo una lista de cosas (dame todas tus llaves) y me devuelven algo más. ¿Esto confundirá a la gente?

+0

Esta es una gran respuesta en stackoverflow: http://stackoverflow.com/questions/8957750/what-are-python-dictionary-view-objects – Exthen

+0

Parece que la URL está muerto. – Borealis

Respuesta

13

De hecho, está obteniendo una lista. Simplemente no es una copia de la lista interna, sino algo que actúa como si fuera una lista, pero solo representa el estado interno.

De la misma manera que se implementa en Java (y probablemente en muchos otros lenguajes/entornos también).

La razón principal es que para muchos casos de uso, devolver una lista completamente separada es innecesario y desperdicia. Requeriría copiar todo el contenido (que puede o no ser mucho).

Si simplemente desea iterar sobre las teclas, entonces no es necesario crear una nueva lista. Y si realmente lo necesita como una lista separada (como una copia), entonces puede crear fácilmente esa lista desde la vista.

6

La respuesta de Joachim Sauer explica muy bien por qué no se devuelve list. Pero esto deja la pregunta de por qué estas funciones no devolverían los iteradores, como lo hizo iteritems etc. en Python 2.

Un iterador es mucho más restrictivo que un contenedor. Por ejemplo, un iterador no permite más de una pasada; si intenta un segundo pase, verá que está vacío. Por lo tanto, operaciones como elem in cont son soportadas por contenedores, pero no pueden ser soportadas por iteradores: una vez que se comprueba si un elemento está "en" el iterador, el iterador se destruye.

Por otro lado, para obtener un contenedor generalmente es necesario realizar una copia, como crear una lista con las teclas del diccionario.

El objeto view tiene lo mejor de dos mundos: se comporta como un contenedor y, sin embargo, no hace una copia del diccionario. De hecho, es una especie de contenedor virtual de solo lectura que funciona al vincular al diccionario subyacente. No sé si se ve en cualquier otro lugar del Python estándar.

Editar:

@AntonyHatchkins: la razón por la que no devuelve una función de generador es que no permitiría una operación rápida in. Sí, in funciona para funciones de generador (cuando las llamas). Es decir, se puede hacer esto:

def f(): 
    for i in range(10): 
    yield i 

5 in f() # True 

Pero de acuerdo con la definición de in, si el lado derecho es un generador, pitón pasará por todos los n elementos del generador - que conduce a O(n) complejidad del tiempo. No hay nada que puedas hacer al respecto porque ese es el único comportamiento significativo que es un generador arbitrario.

Por otro lado, en el caso de la vista de diccionario, puede implementar in de la forma que desee, porque sabe más acerca de los datos que administra. Y, de hecho, in se implementa con O(1) complejidad utilizando una tabla hash. Puede comprobarlo ejecutando

>>> d = dict(zip(range(50000000), range(50000000))) 
>>> 49999999 in d 
True 
>>> 49999999 in iter(d) # kinda how generator function would work 
True 
>>> 

y darse cuenta de lo rápido que el primero in se compara con el segundo in.

+0

Luego va otra pregunta por qué no devolvería las funciones del generador. Son entidades de paso múltiple (lo que también admite operaciones 'elem in cont') y no requieren mucha memoria. –

+0

@AntonyHatchkins editó la respuesta para explicar el motivo – max

+0

Gracias, lo he aprendido yo mismo desde entonces, pero podría ser útil para otras personas también. –

0

Como ya se ha mencionado en la pregunta relacionada, view tiene el método len(), que no tiene el iterador (pero la lista lo tiene).

Otra ventaja de devolver una vista en lugar de una lista es que al menos para las claves tiene una prueba de pertenencia optimizada en O (1) operaciones en lugar de O (N) para la lista (o iterador).

Cuestiones relacionadas