出于好奇,我看到了在字符串域中将对象的id转换为其哈希的操作,而不是使用通常的按位操作,例如^|&~

class A:
    pass

def my_hash(a):
    bits = format(id(a), '064b')
    rot4 = bits[-4:] + bits[:-4]
    n = int(rot4, 2)
    return n

for _ in xrange(10):
    a = A()
    print hash(a) == my_hash(a), hash(a), my_hash(a)


但是正如您在下面看到的那样,下面的功能有时是不正确的。我想念什么?

>>> run /tmp/thing.py
True 272331835 272331835
False -9223372036582443978 9223372037127107638
True 272331835 272331835
False -9223372036582443978 9223372037127107638
True 272331835 272331835
False -9223372036582443978 9223372037127107638
True 272331835 272331835
False -9223372036582443978 9223372037127107638
True 272331835 272331835
False -9223372036582443978 9223372037127107638

最佳答案

哈希产生一个有符号的整数,您的代码产生一个无符号的整数。

对于第一个不正确的结果,id(a)的值为4357309288;在64位中是0000000000000000000000000000000100000011101101110100001101101000。最后4位是1000,将其移到开头可得到1000000000000000000000000000000000010000001110110111010000110110的二进制值,当解释为2's complement signed integer时该二进制值是--9223372036582443978,因为第一位(符号位)设置为。

另一方面,1始终将输入解释为无符号,无长度限制的整数,因此您将得到int(rot4, 2)

Python没有任何“简单”选项来将包含二进制数字的字符串解释为带符号的整数,您可以使用9223372037127107638库来简化操作:

>>> from bitstring import Bits
>>> bits = Bits(int=4357309288, length=64)
>>> bits[-4:]
Bits('0x8')
>>> bits[-4:] + bits[:-4]
Bits('0x80000000103b7436')
>>> (bits[-4:] + bits[:-4]).int
-9223372036582443978L
>>> (bits[-4:] + bits[:-4]).uint
9223372037127107638L


bitstring.int分别为您提供有符号和无符号整数解释。

使用.uint我得到正确的输出:

>>> def my_hash(a):
...     bits = Bits(int=id(a), length=64)
...     return (bits[-4:] + bits[:-4]).int
...
>>> for _ in xrange(10):
...     a = A()
...     print hash(a) == my_hash(a), hash(a), my_hash(a)
...
True -9223372036585854145 -9223372036585854145
True 268921659 268921659
True -9223372036585854145 -9223372036585854145
True 268921659 268921659
True -9223372036585854145 -9223372036585854145
True 268921659 268921659
True -9223372036585854145 -9223372036585854145
True 268921659 268921659
True -9223372036585854145 -9223372036585854145
True 268921659 268921659


如果要坚持使用标准库,请使用this Stack Overflow answer来获取bitstring函数:

>>> twos_comp(9223372037127107638, 64)
-9223372036582443978L


那么您的功能将是:

def my_hash(a):
    bits = format(id(a), '064b')
    rot4 = bits[-4:] + bits[:-4]
    n = twos_comp(int(rot4, 2), 64)
    return n

10-08 04:21