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
Run Code Online (Sandbox Code Playgroud)
没想到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
Run Code Online (Sandbox Code Playgroud)
在这种情况下,集合运算符如何in处理命名元组?它会检查namedtuple的内容吗?
namedtuple并不特别。该元素应该完全相等(__eq__)并且必须具有相似性hash才能通过遏制测试。
>>> hash(pos(1, 1)) == hash(pos(1, 1))
True
>>> pos(1, 1) == pos(1, 1)
True
Run Code Online (Sandbox Code Playgroud)
如果您有兴趣,请参阅此处的实现Github。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);
}
Run Code Online (Sandbox Code Playgroud)
但计算hash本身并不能说明元素是否相等。例如:
>>> hash(-1)
-2
>>> hash(-2)
-2
Run Code Online (Sandbox Code Playgroud)
这意味着如果哈希值相等,则 __eq__需要检查以确认元素是否完全相等。
请注意,我的回答纯粹基于 Cpython 实现。
| 归档时间: |
|
| 查看次数: |
183 次 |
| 最近记录: |