Seite 1 von 1

Hash-bare Riesenobjekte??

Verfasst: Montag 21. Januar 2008, 16:53
von Goswin
Ich habe überhaupt keinen Durchblick, welche Objekte hash-bar sind und welche nicht. Falls ich

Code: Alles auswählen

class gesamte_galaxie(object):
  #Milliarden Attribute und Methoden
  pass
galaxie = gesamte_galaxie()
definiere, dann ist galaxie ohne weiteres hash-bar und als Key in einem Dictionary zu gebrauchen. Anscheinend kann ich die Klasse gesamte_galaxie so komplex gestalten wie ich will, sie BLEIBT hash-bar. Wenn ich aber

Code: Alles auswählen

paar = laecherliches_paar = list([1,2])
definiere, dann ist das auf einmal NICHT hash-bar. Was geht hier vor?

Verfasst: Montag 21. Januar 2008, 17:29
von nkoehring
Hallo Goswin,

ja, Listen sind nicht hashbar. Warum? Wird wohl was mit ihrer Komplexitaet zu tun haben. Tuples sind aber zB hashbar...

Uebrigens sollte man Klassen-Namen in CamelCase schreiben ;)

Verfasst: Montag 21. Januar 2008, 17:54
von gerold
Hallo!

Vielleicht kann der erste Absatz dieser Seite http://docs.python.org/lib/typesmapping.html ein wenig Licht ins Dunkel bringen.

EDIT:

Das auch noch: http://docs.python.org/lib/built-in-funcs.html#l2h-36

mfg
Gerold
:-)

Verfasst: Montag 21. Januar 2008, 18:02
von BlackJack
Und die Standard-`__hash__()`-Implementierung von Objekten basiert einfach auf der Objektidentität. Dabei ist es also egal wie "gross" das Objekt ist, die Identität bleibt immer gleich und auch gleich "gross".

Verfasst: Montag 21. Januar 2008, 19:14
von mitsuhiko
nkoehring hat geschrieben:ja, Listen sind nicht hashbar. Warum? Wird wohl was mit ihrer Komplexitaet zu tun haben. Tuples sind aber zB hashbar...
Tuples sind auch immutable. Listen würden ihren Hash ändern, wenn man Items hinzufügt.

Verfasst: Dienstag 22. Januar 2008, 08:22
von Goswin
Zusatz an Blackjack:

Ich habe in meinem Programm naiverweise Klasseninstanzen als Keys benutzt und KEINE FEHLERMELDUNGEN erhalten. Nun stimmen aber die Ergebnisse nicht, und ich frage mich, ob wegen meiner Key-Verwendung durchaus Fehler entstehen, die aber nicht angezeigt werden.

Im Buch Learning Python, von Lutz & Ascher, heißt es auf Seite 108:
Class instance objects can be used as keys too, as long as they have the proper protocol methods; they need to to tell Python that their value won't change.
Leider wird nicht erklärt, was Protocol methods sind und wie man "Python sagt, dass sich Objekte nicht verändern", Vielleicht gelten diese Einschränkungen auch nur für old-style classes, die in diesem Buch noch einen relativ hohen Stellenwert haben.

Und dann bleibt natürlich noch die Frage, warum (zum Beispiel) Listen nicht ebenfalls anhand ihrer Objekt-Identität gehasht werden. Sind Listen etwa nicht ehrenwerte (first-class) Objekte? Aber ich setze einmal voraus, dass das historisch so gewachsen ist, weil niemand damals auf diese Idee gekommen ist...

Verfasst: Dienstag 22. Januar 2008, 09:32
von BlackJack
Wie gesagt werden bei Objekten erst einmal die Identitäten für den Hash-Wert heran gezogen. Und Vergleiche mit ``==`` und ``!=`` arbeiten auch per Vorgabe erst einmal mit der Objektidentität.

Für Dictionaries wichtig ist, dass diese beiden immer zusammen passen und dass sich der Hash-Wert nicht ändern kann. Zusammenpassen heisst, wenn ``obj1 == obj2`` gilt, dann muss auch ``hash(obj1) == hash(obj2)`` gelten. Wenn Du bei Deinen Klassen also ``__cmp__``, oder ``__eq__``, ``__ne__`` implementierst, musst Du das auch mit ``__hash__`` tun, und zwar so, dass die besagte Bedingung erfüllt ist.

Wenn Du solche Objekte als Schlüssel in Dictionaries verwenden willst, darf sich der Hash nicht durch irgendwelche Operationen verändern, weil die Schlüssel sonst nicht wieder gefunden werden können.

Bei `list` ist der Vergleich vom Listeninhalt abhängig, d.h. der Hashwert würde sich ändern, wenn man die Liste verändert. Deswegen haben die Python-Entwickler vorsichts halber die `__hash__()`-Methode so überschrieben, dass sie unbedingt eine Ausnahme auslöst, die sagt, dass Listen nicht "hashable" sind.