Windows XP, Python 2.5:
hash('http://stackoverflow.com') Result: 1934711907
Google App Engine ( http://shell.appspot.com/ ):
hash('http://stackoverflow.com') Result: -5768830964305142685
Warum ist das so? Wie kann ich eine Hash-Funktion haben, die auf verschiedenen Plattformen (Windows, Linux, Mac) dieselben Ergebnisse liefert?
python
google-app-engine
hash
Denis T.
quelle
quelle
Antworten:
Verwenden hashlib wie
hash()
wurde entwickelt , um verwendet zu werden :und garantiert daher nicht, dass es für alle Python-Implementierungen gleich ist.
quelle
hashlib
für nicht kryptografische Zwecke nicht etwas langsam?hash
95 ns,binascii.crc32
570 ns,hashlib.md5.digest()
1,42 us,murmur.string_hash
234 nshash
verwendet bei jeder Python-Sitzung einen neuen zufällig generierten Salt-Wert. Es wird sich also zwischen Python-Sitzungen ändern.Wie in der Dokumentation angegeben, ist die integrierte Funktion hash () nicht dafür ausgelegt, resultierende Hashes irgendwo extern zu speichern. Es wird verwendet, um den Hashwert des Objekts bereitzustellen, sie in Wörterbüchern zu speichern und so weiter. Es ist auch implementierungsspezifisch (GAE verwendet eine modifizierte Version von Python). Auschecken:
Wie Sie sehen können, unterscheiden sie sich, da hash () die Objektmethode
__hash__
anstelle von 'normalen' Hashing-Algorithmen wie SHA verwendet.In Anbetracht des oben Gesagten besteht die rationale Wahl darin, das Hashlib- Modul zu verwenden.
quelle
int(hashlib.md5(repr(self)).hexdigest(), 16)
(vorausgesetzt, erself.__repr__
wurde als identisch definiert, wenn Objekte identisch sind). Wenn 32 Bytes zu lang sind, können Sie die Größe natürlich reduzieren, indem Sie die Hex-Zeichenfolge vor der Konvertierung in Scheiben schneiden.__repr__
es einzigartig genug ist, könnten Sie es einfach verwendenstr.__hash__
(dhhash(repr(self))
), da Diktate nicht ungleiche Objekte mit demselben Hash verwechseln. Dies funktioniert nur, wenn das Objekt so trivial ist, dass der Repräsentant offensichtlich Identität darstellen kann.a
undb
wie könnte ich das Hashlib-Modul verwenden, um zu sehen, dass die Objekte identisch sind?__hash__()
und__eq__()
in Klassenmethoden .Die Antwort ist absolut keine Überraschung: in der Tat
Wenn Sie also zuverlässige Antworten auf ASCII-Zeichenfolgen erhalten möchten, erhalten Sie einfach die unteren 32 Bit als
uint
. Die Hash-Funktion für Strings ist 32-Bit-sicher und nahezu portabel.Auf der anderen Seite können Sie sich überhaupt nicht darauf verlassen, dass Sie
hash()
ein Objekt abrufen, für das Sie die__hash__
Methode nicht explizit als invariant definiert haben.Über ASCII-Zeichenfolgen funktioniert dies nur, weil der Hash für die einzelnen Zeichen berechnet wird, die die Zeichenfolge bilden, wie folgt:
wobei die
c_mul
Funktion die "zyklische" Multiplikation (ohne Überlauf) wie in C ist.quelle
Die meisten Antworten deuten darauf hin, dass dies auf unterschiedliche Plattformen zurückzuführen ist, aber es steckt noch mehr dahinter. Aus der Dokumentation von
object.__hash__(self)
:Selbst das Ausführen auf demselben Computer führt zu unterschiedlichen Ergebnissen bei verschiedenen Aufrufen:
Während:
Siehe auch die Umgebungsvariable
PYTHONHASHSEED
:Beispielsweise:
quelle
Die Hash-Ergebnisse variieren zwischen 32-Bit- und 64-Bit-Plattformen
Wenn ein berechneter Hash auf beiden Plattformen gleich sein soll, sollten Sie die Verwendung in Betracht ziehen
quelle
Vermutlich verwendet AppEngine eine 64-Bit-Implementierung von Python (-5768830964305142685 passt nicht in 32 Bit), und Ihre Implementierung von Python ist 32 Bit. Sie können sich nicht darauf verlassen, dass Objekt-Hashes zwischen verschiedenen Implementierungen sinnvoll vergleichbar sind.
quelle
Dies ist die Hash-Funktion, die Google in der Produktion für Python 2.5 verwendet:
quelle
Was ist mit Zeichenbit?
Beispielsweise:
Der Hex-Wert steht
0xADFE74A5
für vorzeichenlos2919134373
und signiert-1375832923
. Der korrekte Wert muss signiert sein (Vorzeichenbit = 1), aber Python konvertiert ihn als vorzeichenlos und wir haben nach der Übersetzung von 64 auf 32 Bit einen falschen Hashwert.Seien Sie vorsichtig mit:
quelle
Polynom-Hash für Strings.
1000000009
und239
sind beliebige Primzahlen. Es ist unwahrscheinlich, dass es versehentlich zu Kollisionen kommt. Modulare Arithmetik ist nicht sehr schnell, aber um Kollisionen zu verhindern, ist dies zuverlässiger, als wenn man Modulo eine Potenz von nimmt2
. Natürlich ist es leicht, absichtlich eine Kollision zu finden.quelle
Der Wert von PYTHONHASHSEED kann zum Initialisieren der Hashwerte verwendet werden.
Versuchen:
quelle
Wahrscheinlich wird nur die vom Betriebssystem bereitgestellte Funktion und nicht der eigene Algorithmus abgefragt.
Verwenden Sie , wie in anderen Kommentaren angegeben, die Hashlib oder schreiben Sie Ihre eigene Hash-Funktion.
quelle