2011-08-31 8 views
61

Estoy un poco confundido acerca de lo que puede/no puede usarse como clave para un dict python.¿Por qué no puedo usar una lista como clave dict en python?

dicked = {} 
dicked[None] = 'foo'  # None ok 
dicked[(1,3)] = 'baz' # tuple ok 
import sys 
dicked[sys] = 'bar'  # wow, even a module is ok ! 
dicked[(1,[3])] = 'qux' # oops, not allowed 

Así que una tupla es un tipo inmutable pero si puedo ocultar una lista dentro de ella, entonces no puede ser una clave .. qué no puedo ocultar tan fácilmente una lista dentro de un módulo?

Tenía una vaga idea de que la clave tiene que ser "manejable", pero voy a admitir mi propia ignorancia sobre los detalles técnicos; No sé qué está pasando realmente aquí. ¿Qué iría mal si intentaras usar listas como claves, con el hash como, por ejemplo, su ubicación de memoria?

+1

Aquí es una buena discusión: http://stackoverflow.com/questions/2671211/create-a-dictionary-in-python-which-is-indexed-by-lists – Hernan

+25

Tienes una risa de su nombre de variable. – kindall

Respuesta

21

Hay un buen artículo sobre el tema en la wiki de Python: Why Lists Can't Be Dictionary Keys. Como se explica allí:

¿Qué iría mal si intentara usar listas como claves, con el hash como, por ejemplo, su ubicación de memoria?

Se puede hacer sin realmente romper ninguno de los requisitos, pero conduce a un comportamiento inesperado. Por lo general, las listas se tratan como si su valor se derivara de los valores de su contenido, por ejemplo, al verificar (in-) igualdad. Muchos, comprensiblemente, esperan que pueda usar cualquier lista [1, 2] para obtener la misma clave, donde tendría que mantener exactamente el mismo objeto de la lista. Pero buscar rupturas de valor tan pronto como una lista utilizada como clave se modifique, y para la búsqueda por identidad requiere que se mantenga exactamente en la misma lista, lo cual no es necesario para ninguna otra operación de lista común (al menos no se me ocurre ninguna)

otros objetos tales como módulos y object hacen mucho más importante de su identidad de objetos de todas formas (cuando fue la última vez que tuvo dos objetos de módulo distintas llamadas sys?), Y son comparadas por eso de todos modos.Por lo tanto, es menos sorprendente, o incluso esperado, que ellos, cuando se usan como claves dict, también puedan comparar por identidad en ese caso.

7

Aquí es una respuesta http://wiki.python.org/moin/DictionaryKeys

¿Cuál sería ir mal si se trató de utilizar las listas como claves, con el hash como, por ejemplo, su ubicación en la memoria?

Buscar listas diferentes con los mismos contenidos produciría resultados diferentes, aunque comparar listas con los mismos contenidos las indicaría como equivalentes.

¿Qué tal usar un literal de lista en una búsqueda de diccionario?

9

El problema es que las tuplas son inmutables, y las listas no lo son. Considere lo siguiente

d = {} 
li = [1,2,3] 
d[li] = 5 
li.append(4) 

¿Qué debe devolver d[li]? ¿Es la misma lista? ¿Qué tal d[[1,2,3]]? Tiene los mismos valores, pero ¿es una lista diferente?

En última instancia, no hay una respuesta satisfactoria. Por ejemplo, si la única clave que funciona es la clave original, entonces si no tiene referencia a esa tecla, nunca más podrá acceder al valor. Con cada otra tecla permitida, puede construir una clave sin una referencia al original.

Si mis dos sugerencias funcionan, entonces tiene claves muy diferentes que devuelven el mismo valor, lo que es más que un poco sorprendente. Si solo funciona el contenido original, la clave se estropeará rápidamente, ya que las listas se crean para ser modificadas.

+0

Sí, es la misma lista, por lo que esperaría que 'd [li]' permanezca 5. 'd [[1,2,3]]' se referiría a un objeto de lista diferente como clave, por lo que sería un KeyError . Realmente todavía no veo ningún problema ... excepto que dejar que una clave sea recogida basura puede hacer que algunos de los valores dict sean inaccesibles. Pero eso es un problema práctico, no un problema lógico. – wim

+0

@wim: 'd [list (li)]' siendo un KeyError es parte del problema. En casi * cualquier otro caso de uso *, 'li' no se distinguiría de una nueva lista con contenidos idénticos. Funciona, pero es contraintuitivo para muchos. Además, ¿cuándo fue la última vez que * realmente * tiene que usar una lista como clave dict? El único caso de uso que puedo imaginar es el de todos los elementos por identidad de todos modos, y en ese caso deberías hacer eso en lugar de confiar en que '__hash__' y' __eq__' estén basados ​​en la identidad. – delnan

+0

@delnan ¿Es el problema simplemente que no sería muy útil debido a tales complicaciones? o hay alguna razón por la cual podría realmente romper un dict? – wim

2

Su awnser se puede encontrar aquí:

¿Por listas No Pueden Claves de diccionario

Los recién llegados a menudo se preguntan por qué Python, mientras que la lengua incluye tanto una tupla y un tipo de lista, las tuplas se pueden usar como claves de diccionario, mientras que las listas no lo son. Esta fue una decisión de diseño deliberada, y puede ser mejor explicada en primero entendiendo cómo funcionan los diccionarios de Python.

Fuente & más información: http://wiki.python.org/moin/DictionaryKeys

0

De acuerdo con la documentación de Python 2.7.2:

un objeto es hashable si tiene un valor hash que nunca cambia durante su vida útil (se necesita un hash() método), y puede ser en comparación con otros objetos (necesita un eq() o cmp() método). Los objetos hashables que se comparan iguales deben tener el mismo valor hash.

La capacidad de acceso hace que un objeto se pueda utilizar como una clave de diccionario y un conjunto de miembros , porque estas estructuras de datos utilizan internamente el valor hash.

Todos los objetos incorporados inmutables de Python son hashable, mientras que no hay contenedores mutables (como listas o diccionarios). Los objetos que son instancias de clases definidas por el usuario son controlables por defecto; ellos todos comparan desiguales, y su valor de hash es su id().

Una tupla es inmutable en el sentido de que no puede agregar, quitar o reemplazar sus elementos, pero los elementos en sí mismos pueden ser mutables. El valor hash de la lista depende de los valores hash de sus elementos, por lo que cambia cuando cambia los elementos.

El uso de identificadores para los hash de la lista implicaría que todas las listas se comparan de manera diferente, lo que sería sorprendente e inconveniente.

+0

Eso no responde la pregunta, ¿o sí? 'hash = id' no rompe el invariante al final del primer párrafo, la pregunta es por qué no se hace así. – delnan

+0

@delnan: Agregué el último párrafo para aclarar. –

0

La respuesta simple a su pregunta es que la lista de clases no implementa el método hash que se requiere para cualquier objeto que desee utilizar como clave en un diccionario. Sin embargo, la razón por la cual hash no se implementa de la misma manera que en la clase de tupla (según el contenido del contenedor) es porque una lista es mutable, por lo que la edición de la lista requerirá recalcular el hash, lo que puede significar list ahora se encuentra en el cubo incorrecto dentro de la tabla hash subyacente. Tenga en cuenta que dado que no puede modificar una tupla (inmutable), no se encuentra con este problema.

Como nota al margen, la implementación real de la búsqueda de objetos dicto está basada en el algoritmo D de Knuth Vol. 3, Sec. 6.4. Si tiene ese libro disponible, podría ser una lectura que vale la pena, además, si realmente está interesado, puede echar un vistazo a los comentarios del desarrollador sobre el verdadero implementation of dictobject here.. Explica detalladamente cómo funciona exactamente.También hay un python lecture sobre la implementación de diccionarios que pueden interesarle. Pasan por la definición de una clave y lo que es un hash en los primeros minutos.

15

¿Por qué no puedo usar una lista como una clave dict en python?

>>> d = {repr([1,2,3]): 'value'} 
{'[1, 2, 3]': 'value'} 

(para cualquier persona que se topa con esta pregunta en busca de una manera de evitarlo)

según lo explicado por otros aquí, de hecho, no se puede. Sin embargo, puede utilizar su representación de cadena si realmente desea usar su lista.

+3

Lo siento, realmente no veo tu punto. No es diferente a usar literales de cadena como las teclas. – wim

+3

Verdadero; Acabo de ver tantas respuestas que explican por qué no se pueden usar las listas en términos de 'clave debe ser hashable', que es tan cierto, que quería sugerir una forma de evitarlo, en caso de que alguien (nuevo) lo esté buscando ... – Remi

Cuestiones relacionadas