2010-04-09 8 views
7

Also habe ich ein Quadrat, das aus einer Reihe von Punkten besteht. Zu jedem Zeitpunkt gibt es einen entsprechenden Wert.Zugriff auf einen Wörterbuchwert über benutzerdefinierten Objektwert in Python?

Was ich tun möchte, ist ein Wörterbuch wie dieses bauen:

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 

Allerdings, wenn ich später einen neuen Punkt-Objekt erstellen und versuchen, den Wert des Wörterbuchs für den Zugriff auf den Schlüssel dieses Punktes es doesn ‚t Arbeit ..

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

ich vermute, dass dies, weil python nicht zwei Objekte nicht berücksichtigt mit den gleichen Eigenschaften das gleiche Objekt sein? Gibt es einen Weg dazu? Danke

Antwort

12

Definieren Sie Point.__hash__() und Point.__eq__(), damit sie innerhalb dicts richtig verglichen werden können.

Und während Sie dabei sind, überlegen Sie, Point.__repr__() zu definieren, so dass Sie anständig aussehende Darstellungen Ihrer Point Objekte erhalten.

+0

Danke! Guter Tipp über __repr__, aber ich bin ein wenig verwirrt über den Unterschied zwischen ihm und __str__? – Sam

+1

'__repr __()' wird immer dann verwendet, wenn Sie eine Repräsentation des Objekts benötigen, ohne den String-Wert, z. innerhalb der REPL. –

+1

'__repr__' sollte auch gültiges Python zurückgeben, das als Argument an' eval' übergeben werden kann, um ein Objekt zu erzeugen, das identisch mit demjenigen ist, das reprodiert wird. Es sollte den folgenden String zurückgeben: ''Punkt (% s,% s)'% (self._x, self._y)' –

5

Ja, definieren Sie die Methoden __eq__ und __hash__ für Ihre Point-Klasse.

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

Danke für die Code-Aufteilung, wirklich geholfen! Ich wünschte, ich könnte dich auch als Antwort auswählen. – Sam

+0

Die Methode __hash __() kann einfach als "return (x, y) .__ hash __()" implementiert werden. –

2

Gibt es Gründe, nicht nur ein Tupel verwenden:

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

In diesem Beispiel könnte ich es vielleicht tun, aber in meinem Code hat die Point-Klasse ein paar mehr Eigenschaften, so dass ein Tupel nicht ausreichen würde. – Sam

+0

Überprüfen Sie die NamedTuple-Funktion im Auflistungsmodul. Ich finde es sehr nützlich für die Implementierung von struct-like Objekten und es erstellt Klassen, von denen Sie erben können, wenn Sie zusätzliche Methoden hinzufügen möchten. –

2

Schritte: eine benutzerdefinierte Schlüssel-Klasse implementieren und Hash und Gleichheit Funktion außer Kraft setzen.

z.B.

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) 

main-Methode

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] 

Siehe den Artikel Using custom class as key in python dictionary für nähere Details.

Verwandte Themen