__cmp__ und __hash__: TypeE.: comparison did not return int

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
yanone
User
Beiträge: 7
Registriert: Freitag 12. Januar 2007, 01:05

Hallo zusammen.

Ich benutze eine selbst gebaute Punktkoordinaten-Klasse (x, y).
Zum Vergleichen benutze ich hashlib, um einen Hash-String zu erzeugen, der über Hex in einen Integer verwandelt wird, der dann wiederum in __cmp__ zum Vergleich herangezogen wird.
Leider gibt __hash__ bisweilen long als Datenwert zurück, statt int, und so wird dann ein "TypeError: comparison did not return an int" Fehler geworfen.

Wie kann ich einen Long in ein Int verwandeln?
Oder besser: Gibt es eine sicherere Variante als meine dilettantische Hash-Bildung, um Objekte zu vergleichen?

Vielen Dank.

Code: Alles auswählen

class Point:
	def __init__(self, x, y):
		self.x = x
		self.y = y
	
	def __cmp__(self, other):
		return hash(other) - hash(self)
	
	def __hash__(self):
		import hashlib
		return int(hashlib.md5("%s,%s" % (self.x, self.y)).hexdigest(), 16)
deets

wie waer's mit

Code: Alles auswählen

hash((self.x, self.y))
Bloss weil hash draufsteht, musst du nicht hashlib verwenden... da geht's nur um eine moeglichst kollisionsfreie Funktion, und dafuer ist Tupel-Hashing gut genug.
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Hallo.

Du scheinst ja nicht so richtig zu wissen, was du da tust ^^ Erzeuge den Hashwert einfach mittels.

Code: Alles auswählen

return hash((self.x, self.y))
Wenn du eine Funktion oft aufrufst ist es übrigens keine gute Idee dort immer wieder Module zu importieren. Es gibt nur wenige Ausnahmen in denen es nicht sinnvoll ist, einen Import an den Anfang der Datei zu stellen. Deine __cmp__-Methode ist übrigens sehr zweifelhaft, da der Vergelich von zwei Hashwerten so eigentlich keinen Sinn macht (meistens).
Das Leben ist wie ein Tennisball.
deets

Oh, und noch was - dein __cmp__ ist ziemlich seltsam. Zwar kann man im 2D natuerlich keine normale Ordnung definieren, aber besser als diese quasi-zufaellige Verteilung geht schon, zB erstmal nach X und dann nach Y-Koordinate.

Damit werden Ergebnisse dann vorhersehbar.
yanone
User
Beiträge: 7
Registriert: Freitag 12. Januar 2007, 01:05

EyDu hat geschrieben:

Code: Alles auswählen

return hash((self.x, self.y))
Danke, sieht gut aus.
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

yanone hat geschrieben:
EyDu hat geschrieben:

Code: Alles auswählen

return hash((self.x, self.y))
Danke, sieht gut aus.
Nein eben nicht, bitte lies den Rest der Posts. Bei Ganzzahlen ist `hash` eine Identitätsfunktion und damit passt das noch, man kann sie aber auch direkt weglassen.
Bei Floats gilt das schon nicht mehr, Hashwerte haben hier absolut nicht mehr die Semantik die du haben willst.
Bei Tupeln gilt das ebenfalls.
Hier mal ein kleiner Trace:

Code: Alles auswählen

In [2]: hash((1,2)) == hash((1,2))
Out[2]: True

In [3]: hash((1,2)) > hash((2,2))
Out[3]: False

In [4]: hash((3,2)) > hash((2,2))
Out[4]: True

In [5]: hash((2,3)) > hash((2,2))
Out[5]: True

In [6]: hash((2,200)) > hash((2,2))
Out[6]: False
Wenn du schon bei Tupeln bist und willst, dass die x-Koordinate der erste Schlüssel ist, kannst du sie direkt vergleichen:

Code: Alles auswählen

In [8]: (1,2) > (0,0)
Out[8]: True

In [9]: (1,2) > (2,0)
Out[9]: False

In [10]: (1,200) > (2,0)
Out[10]: False

In [11]: (2,200) > (2,0)
Out[11]: True
Andersherum musst du ein wenig mehr arbeiten.
yanone
User
Beiträge: 7
Registriert: Freitag 12. Januar 2007, 01:05

Hab ich vergessen, zu erwähnen: Ich möchte keine größer/kleiner-Vergleiche anstellen. Nur, ob ein Punkt dem anderen entspricht, also

Code: Alles auswählen

hash(other) - hash(self) = 0
u.a. um die Objekte als Schlüssel in Dictionaries verwenden zu können.

Wenn ich tatsächlich die Positionen vergleichen will, mache ich das situationsbedingt mit den jeweiligen x/y-Koordinaten getrennt.

Kann ich

Code: Alles auswählen

return hash((self.x, self.y))
für den Fall verwenden?
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Dann solltest du nicht ``__cmp__`` benutzen, sondern ``__ne__`` (not equal) und ``__eq__`` (equal) implementieren.
Dann reicht aber auch

Code: Alles auswählen

def __eq__(self, other):
    return (self.x, self.y) == (other.x, other.y)
def __ne__(self, other):
    return (self.x, self.y) != (other.x, other.y)
``hash`` ist zwar verwendbar, aber dann doch ein Mehraufwand.

Code: Alles auswählen

In [1]: hash??
Type:       builtin_function_or_method
Base Class: <type 'builtin_function_or_method'>
String Form:<built-in function hash>
Namespace:  Python builtin
Docstring:
hash(object) -> integer

Return a hash value for the object.  Two objects with the same value have
the same hash value.  The reverse is not necessarily true, but likely.
deets

@cofi

Er muss aber auch __hash__ implementieren, sonst kracht's bei dicts/sets. Ansonsten hast du natuerlich recht, __eq__ und co sind besser.
yanone
User
Beiträge: 7
Registriert: Freitag 12. Januar 2007, 01:05

Hochspannendes Zeug. Macht Laune.
Vielen Dank.
Benutzeravatar
jtschoch
User
Beiträge: 400
Registriert: Freitag 6. Mai 2011, 15:40
Kontaktdaten:

Villeicht macht GMX ein TimeOut oder
es ist begrennzt für solche langen Nutzungen.
------------------------------------------------------------------
Muss ja nicht an Python liegen!
Meine Webseite http://www.develos.de
Forum: http://www.develos.de/forum
Mein Minecraft-Server: jonel.minecraft.to [dynmap(:8123)] | Webseite: http://jonel-minecraft.tk
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

@deets: Nunja, das hatte der OP bisher aber auch nicht erwaehnt ;)

@yanone: Wenn du an Dunder-Methoden rumschraubst, solltest du auf jeden Fall diesen Teil der Sprachreferenz lesen: http://docs.python.org/reference/datamo ... thod-names

@jtschoch: Hast du dich im Thema verirrt?
Benutzeravatar
jtschoch
User
Beiträge: 400
Registriert: Freitag 6. Mai 2011, 15:40
Kontaktdaten:

ja habe ich gemerkt
Meine Webseite http://www.develos.de
Forum: http://www.develos.de/forum
Mein Minecraft-Server: jonel.minecraft.to [dynmap(:8123)] | Webseite: http://jonel-minecraft.tk
Antworten