【问题标题】:What is the default hash of user defined classes?用户定义类的默认散列是什么?
【发布时间】:2015-11-08 04:52:32
【问题描述】:

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?

【问题讨论】:

    标签: python hash cpython


    【解决方案1】:

    相关功能似乎是:

    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,然后被用作type here 中的tp_hash 插槽。)那里的评论似乎给出了不使用指针的原因(这是相同的就像id) 一样。实际上,对函数进行更改的提交是 here,并指出更改的原因是:

    问题 #5186:减少没有散列的对象的散列冲突 方法是将对象指针向右旋转 4 位。

    指的是this 问题,它更详细地解释了进行更改的原因。

    【讨论】:

      【解决方案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

      【讨论】:

        猜你喜欢
        • 2012-05-02
        • 1970-01-01
        • 2016-03-26
        • 1970-01-01
        • 2019-07-26
        • 1970-01-01
        • 2010-12-27
        • 1970-01-01
        • 2014-07-28
        相关资源
        最近更新 更多