Por Favor Ayuda

Alexis Roda alexis.roda.villalonga en gmail.com
Mar Jun 27 18:29:22 CEST 2006


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 :-).

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'}



Si se implementa __hash__() de una forma que no tenga en cuenta el 
"contenido" del diccionario, por ejemplo:

class MiDiccionario(dict):
   def __hash__(self):
     return id(self)

podemos encontrarnos con otro tipo de anomalías:

 >>> d1 = MiDiccionario({'a': 1})
 >>> d2 = MiDiccionario({'a': 1})
 >>> d1 == d2
True
 >>> d1 is d2
False
 >>> d = {}
 >>> d[d1] = 1
 >>> d[d2]
KeyError: {'a': 1}
 >>> d1.__hash__()
-1210493204
 >>> d2.__hash__()
-1210493060


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.



Saludos




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