Python x不在集合中对x!=集合中的每个元素?
假设我们有Python x不在集合中对x!=集合中的每个元素?,python,python-3.x,Python,Python 3.x,假设我们有x=['a','b'] 在声明的幕后发生了什么: x not in {None, False} 这会引发不可损坏类型:“list”错误 我发现的解决方法是写以下内容: x != None and x!= False 但我感到困惑,因为从数学上讲,这两个布尔表达式是等价的。{None,False}是一个集合。集合只能包含可哈希对象,因此只能测试可哈希对象的成员资格。列表是不可散列的 x not in (None, False) 相反,您可以使用元组来执行相同类型的成员比较。元组元素
x=['a','b']
在声明的幕后发生了什么:
x not in {None, False}
这会引发不可损坏类型:“list”
错误
我发现的解决方法是写以下内容:
x != None and x!= False
但我感到困惑,因为从数学上讲,这两个布尔表达式是等价的。
{None,False}
是一个集合。集合只能包含可哈希对象,因此只能测试可哈希对象的成员资格。列表是不可散列的
x not in (None, False)
相反,您可以使用元组来执行相同类型的成员比较。元组元素不需要是可散列的
x not in (None, False)
如果您可以在
集合中输入所有要测试的元素,则意味着所有不可损坏的元素都不属于您的集合(因为您无法将它们放入)
你可以做:
if x.__hash__ and x in {None,False}:
当对象不可散列时,x.uuu hash\uuuu
为None
(其他选项:),第二部分不计算
或者(最好请求原谅而不是允许):
这两种解决方案都比使用列表
或元组
((None,False)
)更快,因为不涉及线性搜索(也就是说,如果测试列表中有很多元素,而不仅仅是两个元素)
以下是官方文件所述:
:
返回一个新的集合或冻结集对象,其元素取自iterable。集合的元素必须是
:
如果一个对象的哈希值在其生存期内从未改变(它需要一个方法),并且可以与其他对象进行比较(它需要一个方法),那么它就是可哈希的。比较相等的可散列对象必须具有相同的散列值。
…
Python的所有不可变内置对象都是可散列的可变容器(如列表或词典)不可用
(就在锚的上方):
成员资格测试操作符(和)通常作为一个序列的迭代来实现。但是,容器对象可以为以下特殊方法提供更高效的实现,这也不要求对象是序列
进入:
- 第#1991行:
- 第1843行:
- 第1823行:
- 第627行:
- 第614行:
从“callstack”(以相反的顺序显示)中可以看出,为了测试成员资格(在
/中而不是在
中),正在对候选成员(“includee”)执行哈希(在所有代码路径上),并且由于列表实例没有哈希功能,解释器会抛出TypeError
决议
有很多方法可以绕过这一点(正如许多其他人已经指出的,其中大部分):
- 使用不要求其元素可散列的容器(列表、元组)
- 对散列成员的测试
- 将成员资格测试包装在try/块中,但块除外
- 对元素使用哈希容器(元组):
x=('a','b')
但是(通常)这些只是解决问题的方法(这是我个人的观点),因为如果你最终将一个列表与“无”和“假”进行比较,代码(生成该列表)可能需要一些重构。我想对集合的成员资格测试与列表的成员资格测试做一个简短的比较
成员资格测试调用dunder(如果类实现此方法)。所以,如果我们写
>>> 1 in [1,2]
这相当于
>>> list.__contains__([1,2],1)
>>> True
如果我们这样做:
>>> [1,2] in [1,2,3]
>>> False #We get False instead of TypeError here
但为什么上述情况不适用于集合?成员资格测试在列表和集合中以不同的方式工作。事实列表和集合的实现方式不同。说到set,它们是使用。这允许设置
执行成员资格测试,即在O(1)
中查找,而在列表
中查找是O(n)
。因此,当对集合执行中的时,\uuuuuu包含
尝试使用计算需要查看的对象的哈希值。自从
在python中,列表是不可破坏的,您会得到错误:TypeError:unhabable type:'list'
。若你们对列表做同样的操作,你们将不会得到任何错误,因为列表不会为成员资格测试计算哈希
简而言之,成员资格测试不能在对象不可损坏的集合上执行。一般来说,所有可变对象(列表、集合、目录)
都是不可损坏的 出于好奇,你能用语言描述一下你真正想要达到的目标吗?我怀疑这两个选项都不是您真正想要的。x
是不可散列的,因此它不能在您的set
中。您正在尝试查找列表对象是否在两个值的集合中(即集合中的两个值之一是否为列表)。列表不能散列,因此不能作为集合的一部分,因此不可比较。你想让这个操作做什么?set()
中的[]引发错误而不是计算为False
,有什么理由吗?@Patrick Python警告你一些无意义的操作,而不是悄悄地失败。因此,如果x
是不可损坏的,那么它就不在集合中:)@Jean-Françoisfare是的,是的。我认为除了TypeError:…
会更像pythonic。@deceze是的,我想使用短路。异常强制创建函数。在我提供的链接中还有其他选择(比如测试类型aganstcollections.Hashable
,但我怀疑这会很慢),异常不会强制创建函数;这取决于使用此代码的上下文以及您希望它的详细程度/简洁程度。当TypeError
发生或没有发生时,您可能会中止整个操作,因为x
显然是错误的类型…
static int
set_contains_key(PySetObject *so, PyObject *key)
{
setentry entry;
Py_hash_t hash;
if (!PyUnicode_CheckExact(key) ||
(hash = ((PyASCIIObject *) key)->hash) == -1) { // @TODO - cfati: MARK THIS LINE
hash = PyObject_Hash(key);
if (hash == -1)
return -1;
}
entry.key = key;
entry.hash = hash;
return set_contains_entry(so, &entry); // @TODO - cfati: MARK THIS LINE
}
static int
set_contains_entry(PySetObject *so, setentry *entry)
{
PyObject *key;
setentry *lu_entry;
lu_entry = set_lookkey(so, entry->key, entry->hash); // @TODO - cfati: MARK THIS LINE
if (lu_entry == NULL)
return -1;
key = lu_entry->key;
return key != NULL && key != dummy;
}
>>> 1 in [1,2]
>>> list.__contains__([1,2],1)
>>> True
>>> [1,2] in [1,2,3]
>>> False #We get False instead of TypeError here