Las claves del diccionario de Python (que son objetos de clase) se comparan con comparador múltiple

Estoy usando objetos personalizados como claves en el diccionario de python. Estos objetos tienen algunos métodos predeterminados de hash y eq que se usan en comparación por defecto. Pero en alguna función necesito usar una forma diferente de comparar estos objetos. Entonces, ¿hay alguna manera de anular o pasar un nuevo comparador para estas comparaciones clave solo para esta función específica?

Actualizado: mi clase tiene el siguiente tipo de funcionalidad (aquí no puedo editar el método hash , afectará mucho en otros lugares)

class test(object): def __init__(self,name,city): self.name=name self.city=city def __eq__(self,other): hash_equality= (self.name==other.name) if(not hash_equality): #check with lower return (self.name.lower()==other.name.lower()) def __hash__(self): return self.name.__hash__() my_dict={} a=test("a","city1") my_dict[a]="obj1" b=test("a","city2") print b in my_dict #prints true c=test("A","city1") print c in my_dict #prints false print c in my_dict.keys() #prints true # my_dict[c] throw error 

Esta es la funcionalidad normal. Pero en un método específico quiero anular / o pasar un nuevo comparador personalizado donde el nuevo código hash es como

 def __hash__(self): return self.name.lower().__hash__() 

para que c in my_dict devuelva ture

o my_dict[c] will return "obj1"

Lo siento por tantas actualizaciones.

Al igual que en la clasificación, podemos pasar un método personalizado como comparador, ¿hay alguna manera de hacer lo mismo aquí?

La única forma de hacer que esto funcione es crear una copia de su diccionario utilizando la nueva función hash y de comparación. La razón es que el diccionario necesita volver a rellenar cada clave almacenada con la nueva función hash para que la búsqueda funcione como desee. Dado que no puede proporcionar una función hash personalizada a un diccionario (siempre usa la de los objetos clave), su mejor opción probablemente sea envolver sus objetos en un tipo que use su hash personalizado y funciones de comparación.

 class WrapKey(object): __init__(self, wrapee): self._wrapee = wrapee __hash__(self): return self._wrapee.name.lower().__hash__() __eq__(self, other): return self._wrapee.name == other._wrapee.name def func(d): d_copy = dict((WrapKey(key), value) for key, value in d.iteritems()) # d_copy will now ignore case 

Eche un vistazo a los métodos de comparación que puede definir en un objeto.

Dependiendo de lo que quieras hacer, __cmp__ también podría ser interesante.

Un pequeño truco para esta situación:

 class test(object): def __init__(self,name,city,hash_func=None): self.name=name self.city=city self.hash_func = hash_func def __eq__(self,other): return self.__hash__()==other.__hash__() def __hash__(self): if self.hash_func is None: return self.name.__hash__() else: return self.hash_func(self) my_dict={} a=test("a","city1") my_dict[a]="obj1" b=test("a","city2") print b in my_dict #prints true c=test("A","city1") print c in my_dict #Prints false c.hash_func = lambda x: x.name.lower().__hash__() print c in my_dict #Now it prints true 

No puede cambiar el hash almacenado en el dict, pero puede cambiar el uso del hash para buscar. Por supuesto, esto lleva a algo raro como este.

 my_dict={} a=test("a","city1") my_dict[a]="obj1" a.hash_func = lambda x: 1 for key in my_dict: print key in my_dict # False 

ahora estoy usando un dict personalizado (clase derivada de dict) que toma el comparador como parámetro y he anulado los contenidos y getitems () que verifican y dan valor en función del comparador.

Pasos: Implementar una clase de clave personalizada y anular la función de hash e igualdad.

p.ej

 class CustomDictKey(object): def __init__(self, param1, param2): self._param1 = param1 self._param2 = param2 # overriding hash and equality function does the trick def __hash__(self): return hash((self._param1, self._param2)) def __eq__(self, other): return ( ( self._param1, self._param2 ) == ( other._param1, other._param2) ) def __str__(self): return "param 1: {0} param 2: {1} ".format(self._param1, self._param2) 

método principal

 if name == 'main': # create custom key k1 = CustomDictKey(10,5) k2 = CustomDictKey (2, 4) dictionary = {} #insert elements in dictionary with custom key dictionary[k1] = 10 dictionary[k2] = 20 # access dictionary values with custom keys and print values print "key: ", k1, "val :", dictionary[k1] print "key: ", k2, "val :", dictionary[k2] 

Consulte el enlace Uso de la clase personalizada como clave en el diccionario de Python para obtener detalles completos.