2010-04-22 3 views
9

I definiert eine Klasse:Python-Hash() kann Long-Integer nicht behandeln?

 
class A: 
    ''' hash test class 
    >>> a = A(9, 1196833379, 1, 1773396906) 
    >>> hash(a) 
    -340004569 

    This is weird, 12544897317L expected. 
    ''' 
    def __init__(self, a, b, c, d): 
     self.a = a 
     self.b = b 
     self.c = c 
     self.d = d 

    def __hash__(self): 
     return self.a * self.b + self.c * self.d 

Warum im doctest, Hash() Funktion eine negative ganze Zahl gibt?

Antwort

10

Es scheint auf 32-Bit beschränkt zu sein. Wenn Sie this question lesen, sieht es so aus, als hätte Ihr Code das erwartete Ergebnis auf einer 64-Bit-Maschine erzeugt (mit diesen bestimmten Werten, da das Ergebnis in 64 Bit passt).

Die Ergebnisse der integrierten hash-Funktion sind plattformabhängig und auf die native Wortgröße beschränkt. Wenn Sie einen deterministischen, plattformübergreifenden Hash-Wert benötigen, sollten Sie das Modul verwenden.

4

Da der Zweck einer Hash-Funktion ist, eine Reihe von Eingaben zu machen und sie über eine Reihe von Schlüsseln zu verteilen, gibt es keinen Grund, dass diese Schlüssel positive ganze Zahlen sein müssen.

Die Tatsache, dass die Python-Hashfunktion negative Ganzzahlen zurückgibt, ist nur ein Implementierungsdetail und ist notwendigerweise auf Long-Ints beschränkt. Zum Beispiel ist Hash ('abc') auf meinem System negativ.

7

Siehe object.__hash__

Beachten Sie, dass

in Version geändert 2.5: __hash__() kann jetzt auch ein Long-Integer-Objekt zurück; Die 32-Bit-Ganzzahl wird dann aus dem Hash des Objekts abgeleitet.

In Ihrem Fall erwartete 12544897317L ein Objekt lange ganze Zahl ist,

Python abgeleitet, um die 32-Bit-Ganzzahl von -340.004.569 (12544897317 & 0xFFFFFFFF) - (1<<32)

Python abgeleitet, um die 32-Bit-Ganzzahl von hash (12544897317L), die -340004569

der Algorithmus ergibt, ist so etwas wie dieses:

def s32(x): 
    x = x & ((1<<32)-1) 
    if x & (1<<31): 
     return x - (1<<32) 
    else: 
     return x 

def hash(x): 
    h = 0 
    while x: 
     h += s32(x) 
     x >>= 32 
    return h 
+2

Nitpick: (12544897317 & 0xFFFFFFFF) - (1 << 32) ist nicht -340004569; es ist -340004571. Python erreicht tatsächlich die 32-Bit-Nummer durch * Re-Hashing *; d.h. Berechnen von Hash (12544897317). Dies ist besser, weil es nicht nur die höherwertigen Bits des ursprünglichen Hash-Werts wegwirft, sondern diese stattdessen in den endgültigen Hash-Wert mischt. –

+0

@Mark Dickinson, uh-huh, danke – inv