2010-04-09 22 views
7

Así que tengo un cuadrado que se compone de una serie de puntos. En cada punto hay un valor correspondiente.¿Acceder a un valor de diccionario por valor de objeto personalizado en Python?

Lo que quiero hacer es construir un diccionario de la siguiente manera:

class Point: 
    def __init__(self, x, y): 
     self._x = x 
     self._y = y 


square = {}  
for x in range(0, 5): 
     for y in range(0, 5): 
      point = Point(x,y) 
      square[point] = None 

Sin embargo, si más adelante se crea un nuevo objeto de punto y tratar de acceder al valor del diccionario con la clave de ese punto que doesn 't trabajo ..

>> square[Point(2,2)] 
Traceback (most recent call last): 
    File "<pyshell#19>", line 1, in <module> 
    square[Point(2,2)] 
KeyError: <__main__.Point instance at 0x02E6C378> 

supongo que esto se debe pitón no tiene en cuenta dos objetos con las mismas propiedades que ser el mismo objeto? ¿Hay alguna forma de evitar esto? Gracias

Respuesta

12

Defina Point.__hash__() y Point.__eq__() para que se puedan comparar correctamente dentro de los dicts.

Y mientras lo hace, considere la definición de Point.__repr__() para que obtenga representaciones de aspecto decente de sus objetos Point.

+0

Gracias! Un buen consejo sobre __repr__ pero estoy un poco confundido acerca de la diferencia entre __str__? – Sam

+1

'__repr __()' se usa siempre que necesite una representación del objeto, sin querer realmente el valor de la cadena, p. dentro de REPL. –

+1

'__repr__' también debe devolver python válido, que podría pasarse como un arg a' eval' para crear un objeto idéntico al que se está imprimiendo. Debería devolver la siguiente cadena: ''Point (% s,% s)'% (self._x, self._y)' –

5

Sí, defina los métodos __eq__ y __hash__ en su clase Point.

class Point: 
    def __init__(self, x, y): 
     self._x = x 
     self._y = y 

    def __eq__(self, other): 
     return self._x == other._x and self._y == other._y 

    def __hash__(self): 
     #This one's up to you, but it should be unique. Something like x*1000000 + y. 
+0

¡Gracias por el desglose del código, realmente me ayudó! Ojalá pudiera elegir como una respuesta también. – Sam

+0

El método __hash __() solo se puede implementar como "return (x, y) .__ hash __()". –

2

algún motivo no sólo tiene que utilizar una tupla:

>>> s={} 
>>> s[1,2]=5 
>>> s 
{(1, 2): 5} 
>>> s[1,2] 
5 
+0

En ese ejemplo, supongo que podría, pero en mi código, la clase Point tiene algunas propiedades más, por lo que una tupla no sería suficiente. – Sam

+0

Echa un vistazo a la función namedtuple en el módulo de colecciones. Lo encuentro muy útil para implementar objetos similares a estructuras, y crea clases de las que puede heredar si desea agregar métodos adicionales. –

2

pasos: Implementar una clase clave personalizada y anulan la función hash y la 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] 

remitir el artículo Using custom class as key in python dictionary para más detalles.

Cuestiones relacionadas