python-3.x 哈希集中存在命名元组

aemubtdh  于 2022-11-19  发布在  Python
关注(0)|答案(2)|浏览(151)
In [1]: x = set()
In [2]: pos = collections.namedtuple('Position', ['x','y'])
In [4]: x.add(pos(1,1))
In [5]: x
Out[5]: {Position(x=1, y=1)}
In [6]: pos(1,1) in x
Out[6]: True
In [8]: pos(1,2) in x
Out[8]: False

我并不期望第6行pos(1,1) in x能正常工作,因为pos(1,1)每次创建的对象ID都不一样。

In [9]: id(pos(1,1))
Out[9]: 140290954200696
In [10]: id(pos(1,1))
Out[10]: 140290954171016

在这种情况下,set in操作符如何处理命名元组?它是否检查命名元组的内容?

bmp9r5qi

bmp9r5qi1#

namedtuple并不特殊。元素应该完全相等(__eq__),并且必须具有类似的hash才能通过包含测试。

>>> hash(pos(1, 1)) == hash(pos(1, 1))
True
>>> pos(1, 1) == pos(1, 1)
True

如果您有兴趣查看此处的实现,set().__contains__(y)首先必须计算yhash值。

static int
set_contains_key(PySetObject *so, PyObject *key)
{
    Py_hash_t hash;

    if (!PyUnicode_CheckExact(key) ||
        (hash = _PyASCIIObject_CAST(key)->hash) == -1) {
        hash = PyObject_Hash(key);
        if (hash == -1)
            return -1;
    }
    return set_contains_entry(so, key, hash);
}

但是单独计算hash并不能说明元素是否相等。

>>> hash(-1)
-2
>>> hash(-2)
-2

这意味着如果散列值相等,则需要__eq__检查来确认元素是否完全相等。
请注意,我的答案完全基于Cpython实现。

4ioopgfo

4ioopgfo2#

可散列对象的元组是可散列的,因此它可以用作集合的成员,从而通过in检查。
由于您使用数字作为元组值(显然是可散列的),因此散列整个元组没有问题。

相关问题