2012-03-23 15 views
6

Estoy utilizando objetos personalizados como claves en el diccionario de Python. Estos objetos tienen algunos hash predeterminados y eq métodos definidos que se usan en la comparación predeterminada 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 esta comparación de clave solo para esta función específica?Python dictionary keys (que son objetos de clase) comparación con comparer múltiple

Actualizado: Mi clase presenta los siguientes tipo de funcionalidad (aquí no puedo editar de hash método, va a 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 que quiero para anular/o pasar a un nuevo comparador personalizada donde el nuevo código de hash es como

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

de modo que los c in my_dict vuelve Türe

o my_dict[c] will return "obj1"

Lo siento por lo que muchas actualizaciones

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

+0

He leído mal la pregunta (se trataba de ordenar). Aún así, ¿puede proporcionar algún código para ilustrar lo que está tratando de lograr? –

+0

necesito un método de comparación específico en una sola función.Y ordenando la manera, quiero decir que como en sort podemos pasar el comparador, ¿puede hacerse al verificar las claves? – gsagrawal

+0

Por cierto, ¿está seguro de que quiere su '__eq__'-function para comparar hashes? Los valores hash pueden tener colisiones, por lo que es posible que tenga un comportamiento inesperado en algunos casos. –

Respuesta

0

ahora estoy usando dict personalizado (clase derivada de dict), que toma comparador como parámetro y he anulado la contiene y getItems() que comprueba y dar valor basado en el comparador.

0

Eche un vistazo a comparison methods que puede definir en un objeto.

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

+0

actualizó la descripción de la pregunta. __cmp__ no ayuda aquí – gsagrawal

4

La única forma de hacerlo funcionar es crear una copia de su diccionario utilizando el nuevo hash y la función de comparación. La razón es que el diccionario necesita volver a configurar cada clave almacenada con la nueva función hash para que la búsqueda funcione como lo desee. Como no puede proporcionar una función hash personalizada a un diccionario (siempre usa uno de los objetos clave), la mejor opción es 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 
0

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 se puede cambiar el hash almacenado en el dict, pero se puede cambiar el uso de hash para mirar hacia arriba. Por supuesto, esto conduce a algo raro como esto

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 
0

Pasos: Implemente una clase de clave personalizada y anule la función 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) 

principal método

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 Using custom class as key in Python dictionary para más detalles.

Cuestiones relacionadas