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

时间:2018-02-13 17:43:13

标签: python hash set immutability

即使集合不可删除,其他集合中的成员资格检查也是如此:

>>> set() in {frozenset()}
True

我期望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'

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

2 个答案:

答案 0 :(得分:7)

set_containsimplemented like this

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;
}

因此,这将直接委托给set_contains_key,它将基本上散列对象,然后使用其散列查找元素。

如果对象不可删除,set_contains_key会返回-1,因此我们进入if。在这里,我们检查显式传递的key对象是一个集合(或一个集合子类型的实例)我们以前是否遇到类型错误。这表明我们尝试使用set进行包含检查,但失败了,因为它不可用。

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

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

>>> set() in {frozenset()}
True
>>> set(('a')) in { frozenset(('a')) }
True

答案 1 :(得分:5)

the documentation for sets的最后一行讨论了这个问题:

  

注意__contains__()remove()discard()elem参数   方法可以是set。支持搜索等效项   frozenset,从elem创建一个临时的。{/ p>