如何/为什么{frozenset()}中的set()有效?

wim*_*wim 15 python hash set immutability

即使集合不可用,会员检查其他集合工作:

>>> set() in {frozenset()}
True
Run Code Online (Sandbox Code Playgroud)

我期望TypeError: unhashable type: 'set',与Python中的其他行为一致:

>>> set() in {}  # doesn't work when checking in dict
TypeError: unhashable type: 'set'
>>> {} in {frozenset()}  # looking up some other unhashable type doesn't work
TypeError: unhashable type: 'dict'
Run Code Online (Sandbox Code Playgroud)

那么,如何在其他集合中设置成员身份?

pok*_*oke 7

set_contains实现这样的:

static int
set_contains(PySetObject *so, PyObject *key)
{
    PyObject *tmpkey;
    int rv;

    rv = set_contains_key(so, key);
    if (rv < 0) {
        if (!PySet_Check(key) || !PyErr_ExceptionMatches(PyExc_TypeError))
            return -1;
        PyErr_Clear();
        tmpkey = make_new_set(&PyFrozenSet_Type, key);
        if (tmpkey == NULL)
            return -1;
        rv = set_contains_key(so, tmpkey);
        Py_DECREF(tmpkey);
    }
    return rv;
}
Run Code Online (Sandbox Code Playgroud)

因此,这将直接委托给set_contains_key对象,然后使用其哈希查找元素.

如果对象不可用,则set_contains_key返回-1,因此我们进入内部if.在这里,我们明确检查传递的key对象是否是一个集合(或一个set子类型的实例)以及我们之前是否有类型错误.这表明我们尝试使用set但是失败的包含检查,因为它是不可用的.

在这种情况下,我们现在frozenset从中创建一个新的setset_contains_key再次尝试使用包含检查.而且由于frozensets可以适当地清洗,我们能够以这种方式找到我们的结果.

这解释了为什么即使集合本身不可清除,以下示例也能正常工作:

>>> set() in {frozenset()}
True
>>> set(('a')) in { frozenset(('a')) }
True
Run Code Online (Sandbox Code Playgroud)


Pat*_*ugh 5

s 的文档set的最后一行讨论了这个:

请注意,该elem参数的__contains__(),remove()discard() 方法可能是一个set.为了支持搜索等效项 frozenset,创建了一个临时的elem.