docs错误地声称
默认情况下,作为用户定义类实例的对象是可清除的;它们都比较不相等(除了自己),它们的哈希值是
id()
虽然我记得这一次是正确的,但是在当前版本的python(v2.7.10,v3.5.0)中,这样的对象散列等于它们的id显然不正确。
>>> class A:
... pass
...
>>> a = A()
>>> hash(a)
-9223372036578022804
>>> id(a)
4428048072
在文档的another part中,它表示哈希是来自id的派生。何时/为什么实施会发生变化,而哈希“返回”的数字是如何从“id”中获得的?
答案 0 :(得分:4)
相关功能似乎是:
Py_hash_t
_Py_HashPointer(void *p)
{
Py_hash_t x;
size_t y = (size_t)p;
/* bottom 3 or 4 bits are likely to be 0; rotate y by 4 to avoid
excessive hash collisions for dicts and sets */
y = (y >> 4) | (y << (8 * SIZEOF_VOID_P - 4));
x = (Py_hash_t)y;
if (x == -1)
x = -2;
return x;
}
(该代码来自here,然后用作tp_hash
here中的type
广告位。)这里的评论似乎没有给出理由直接使用指针(与id
相同)。实际上,将该更改引入函数的提交是here,并声明更改的原因是:
问题#5186:减少没有哈希的对象的哈希冲突 方法将对象指针向右旋转4位。
指的是this问题,这解释了更改原因的更多原因。
答案 1 :(得分:2)
由于issue #5186,这在2009年发生了变化;通常的id()
值导致了太多的冲突:
In the issue 5169 discussion, Antoine Pitrou suggested that for an object
x without a `__hash__` method, `id()/8` might be a better hash value than
`id()`, since dicts use the low order bits of the hash as initial key, and
the 3 lowest bits of an `id()` will always be zero.
current implementation获取id并旋转它以产生更多变化的值:
long
_Py_HashPointer(void *p)
{
long x;
size_t y = (size_t)p;
/* bottom 3 or 4 bits are likely to be 0; rotate y by 4 to avoid
excessive hash collisions for dicts and sets */
y = (y >> 4) | (y << (8 * SIZEOF_VOID_P - 4));
x = (long)y;
if (x == -1)
x = -2;
return x;
}
这导致了14%到34%的加速,具体取决于所进行的测试。
词汇表已经过时了;我见到你了already opened an issue with the project。