Por Favor Ayuda

Chema Cortes pych3m4 en gmail.com
Mar Jun 27 19:22:43 CEST 2006


2006/6/27, Alexis Roda <alexis.roda.villalonga en gmail.com>:
> En/na Chema Cortes ha escrit:
> > 2006/6/23, Alexis Roda <alexis.roda.villalonga en gmail.com>:
> >> La clave debe ser "hashable", los diccionarios no lo son. Si no recuerdo
> >> mal los objetos mutables (listas, diccionarios ...) no pueden actuar
> >> como claves de un diccionario. Los objetos inmutables ("string", tuplas
> >> ...) si pueden. Por supuesto nada te impide derivar una clase
> >> MiDiccionario(dict) que si sea hashsable.
> >
> > Para que quede claro como podría ser:
> >
> > class MiDiccionario(dict):
> >  def __hash__(self):
> >    return tuple(self.items()).__hash__()
> >
> > d=MiDiccionario(  {'clave1':"Esta es la clave 1", 2:"otra clave"} )
> > print d
> > --> {2: 'otra clave', 'clave1': 'Esta es la clave 1'}
> >
> > r={d:d}
> > print r
> > --> {{2: 'otra clave', 'clave1': 'Esta es la clave 1'}: {2: 'otra
> > clave', 'clave1': 'Esta es la clave 1'}}
>
> Ya que estamos vamos a completar los detalles :-).

Muy buen análisis.


> Hacer un diccionario "hashable" tiene su miga. Si el valor devuelto por
> __hash__() depende del contenido del diccionario (claves y/o valores) su
> valor cambiará al cambiar el diccionario. Eso nos obliga a tratar las
> instancias de MiDiccionario como de solo lectura una vez utilizadas como
> claves:
>
>  >>> d.__hash__()
> -616709607
>  >>> d['otra clave'] = 12345
>  >>> d.__hash__()
> -2015796712
>  >>> print r[d]
> KeyError: {'otra clave': 12345, 2: 'otra clave', 'clave1': 'Esta es la
> clave 1'}

Es algo lioso de explicar, pero el problema está en que 'd' no debe
verse como la clave. Una vez creada la instancia de MiDiccionario, ya
no hay relación con 'd'. En este código habría que haber comprobado
que todavía existe la clave:

>>> r.has_key(d)
False
>>> print r.keys()
{2: 'otra clave', 'clave1': 'Esta es la clave 1'}

En definitiva, no ha cambiado la instancia MiDiccionario; sólo la
clave por la que preguntas. Hacer la clave de sólo lectura no
mejoraría mucho más.

Al haber usado en MiDiccionario el mismo __hash__ de las tuplas, estoy
garantizando que dos diccionarios con los mismos "items()" funcionan
de modo equivalente. Observa lo siguiente :

>>> d=MiDiccionario( {1:"clave"} )
>>> f=MiDiccionario( {1:"clave"} )
>>> d is f
False
>>> r={d:d}
>>> r[f]
{1: 'clave'}

Es justo el comportamiento esperado.

> Mi conclusión seria que antes de utilizar un diccionario como clave de
> otro diccionario habría que pensarlo cinco minutos. La idea de utilizar
> un objeto (potencialmente) cambiante como identificador de otro objeto
> resulta un tanto ... extraña.

Ya resulta extraño utilizar tuplas como para liarse con otras cosas.

Por cierto, que también pueden ser claves de diccionarios esos
olvidados en python que son los números complejos. Serían un buen
ejemplo de "cosa rara" que se puede usar como claves:

>>> z=1+2j
>>> d={z:"primer valor"}
>>> d
{(1+2j):"primer valor"}
>>> z=-1j
>>> d.has_key(z)
False




Más información sobre la lista de distribución Python-es