命名元组存在于哈希集中

问题描述 投票:0回答:2
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

在这种情况下,集合

in
运算符如何作用于命名元组?它会检查namedtuple的内容吗?

python python-3.x python-2.7 python-3.6 python-2.x
2个回答
6
投票

namedtuple
并不特别。该元素应该完全相等(
__eq__
)并且必须具有相似的
hash
才能通过遏制测试。

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

如果您有兴趣,请参阅此处的实现

set().__contains__(y)
首先必须计算
hash
y
值。

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 实现。


0
投票

可哈希对象的元组是可哈希的,因此它可以用作集合的成员,从而通过

in
检查。
由于您使用数字作为元组值,这显然是可哈希的,因此对整个元组进行哈希处理是没有问题的。

© www.soinside.com 2019 - 2024. All rights reserved.