2010-04-09 17 views
7

Quindi ho un quadrato composto da una serie di punti. In ogni punto c'è un valore corrispondente.Accesso a un valore di dizionario in base al valore dell'oggetto personalizzato in Python?

Quello che voglio fare è costruire un dizionario come questo:

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 

Tuttavia, se poi creo un nuovo oggetto punto e provo ad accedere al valore del dizionario con la chiave di quel punto doesn 't lavoro ..

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

sto indovinando che questo è perché Python non considera due oggetti con le stesse proprietà di essere lo stesso oggetto? C'è un modo per aggirare questo? Grazie

risposta

12

Definire Point.__hash__() e Point.__eq__() in modo che possano essere confrontati correttamente in dict.

E mentre ci sei, considera la possibilità di definire Point.__repr__() in modo da ottenere rappresentazioni decenti degli oggetti Point.

+0

Grazie! Un buon consiglio su __repr__ ma sono un po 'confuso riguardo la differenza tra questo e __str__? – Sam

+1

'__repr __()' viene utilizzato ogni volta che è necessaria una rappresentazione dell'oggetto, senza realmente volere il valore di stringa, ad es. all'interno della REPL. –

+1

'__repr__' dovrebbe anche restituire python valido, che potrebbe essere passato come argomento a' eval' per creare un oggetto identico a quello che viene repr'd. Dovrebbe restituire la seguente stringa: ''Punto (% s,% s)'% (self._x, self._y)' –

5

Sì, definire i metodi __eq__ e __hash__ sulla classe 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

Grazie per l'interruzione del codice, davvero aiutato! Vorrei poterti scegliere anche come risposta. – Sam

+0

Il metodo __hash __() può essere implementato come "return (x, y) .__ hash __()". –

2

Qual è il motivo per non utilizzare solo una tupla:

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

In quell'esempio credo che potrei, ma nel mio codice la classe Point ha alcune proprietà in più, quindi una tupla non sarebbe sufficiente. – Sam

+0

Controlla la funzione namedtuple nel modulo collections. Trovo molto utile per l'implementazione di oggetti simili a strutture e crea classi da cui si può ereditare se si desidera aggiungere ulteriori metodi. –

2

Passi: implementare una classe chiave personalizzata e sovrascrivere hash e la funzione uguaglianza.

ad es.

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) 

principale metodo

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] 

consultare l'articolo Using custom class as key in python dictionary per i dettagli completi.

Problemi correlati