![](/img/trans.png)
[英]Can I set default values with matplotlib and pandas for each x tick?
[英]x not in set versus x != each element in the set?
假设我们有x = ['a', 'b']
。
发言内容正在发生什么:
x not in {None, False}
提出unhashable type: 'list'
错误?
我发现的解决方法是改为:
x != None and x!= False
但我很困惑,因为从数学上讲,两个布尔表达式都是等价的。
以下是官方文档中的说明:
[Python 3]:类集 ( [iterable] ) :
返回一个新的set或frozenset对象,其元素取自iterable 。 集合的元素必须是可以 清除的 。
一个目的是可哈希如果它有一个哈希值其寿命(它需要一个在这期间从不改变__hash __()方法),并且可相对于其他对象(它需要一个__eq __()方法)。 比较相等的可哈希对象必须具有相同的哈希值。
...
所有Python的不可变内置对象都是可清除的; 可变容器(例如列表或词典)不是 。
[Python 3]:对象。 __contains __ ( self,item ) (在锚点上方):
成员资格测试运算符( in和not in )通常实现为序列的迭代。 但是, 容器对象可以使用更高效的实现提供以下特殊方法,这也不要求对象是序列。
进入[GitHub]:python / cpython - (v3.5.4)cpython / Objects / setobject.c :
线#1991 :
static PyMethodDef set_methods[] = { {"add", (PyCFunction)set_add, METH_O, add_doc}, {"clear", (PyCFunction)set_clear, METH_NOARGS, clear_doc}, {"__contains__",(PyCFunction)set_direct_contains, METH_O | METH_COEXIST, // @TODO - cfati: MARK THIS LINE
第#1843行 :
static PyObject * set_direct_contains(PySetObject *so, PyObject *key) { long result; result = set_contains(so, key); // @TODO - cfati: MARK THIS LINE if (result == -1) return NULL; return PyBool_FromLong(result); }
第#1823行 :
static int set_contains(PySetObject *so, PyObject *key) { PyObject *tmpkey; int rv; rv = set_contains_key(so, key); // @TODO - cfati: MARK THIS LINE if (rv == -1) { 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); // @TODO - cfati: MARK THIS LINE Py_DECREF(tmpkey); } return rv; }
#627行 :
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 }
#614行 :
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; }
从“callstack”(以相反顺序呈现)中可以看出,为了测试成员资格( in
/ not in
),正在候选成员(“ includee ”)上执行散列 (在所有代码路径上),并且由于list实例没有散列函数,解释器吐出TypeError 。
有很多方法可以解决这个问题(正如许多其他人已经指出的那样):
x = ('a', 'b')
但(通常)这些只是解决问题的方法(这是我个人的意见),因为如果你最终将列表与None和False进行比较,那么代码(产生该列表)可能会使用一些重构。
如果您可以在set
输入要测试的所有元素,则表示所有不可用元素都不属于您的集合(因为您无法将它们放入)
你可以这样做:
if x.__hash__ and x in {None,False}:
当object不可x.__hash__
时, x.__hash__
为None
(其他替代方法: 询问“是否可以”关于Python值 )并且第二部分未被评估。
或(更好地请求宽恕而非许可):
def belongs(x):
try:
return x in {None,False}
except TypeError: # unhashable type
return False
两种解决方案都比使用list
或tuple
更快( (None,False)
),因为没有涉及线性搜索(即如果测试列表中有很多元素,对于仅2个元素则不正确)
{None, False}
是一组。 集合只能包含可散列对象,因此您只能测试可散列对象的成员资格。 列表不可清洗。
相反,您可以使用元组来执行相同类型的成员资格比较。 元组元素不需要是可以清除的。
x not in (None, False)
我想对set
vs list
成员资格测试做一个简短的比较
成员资格测试调用__contains__
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
但为什么以上情况不适用于套装? 成员资格测试在列表和集合中以不同的方式工作。 事实列表和集合的实现方式不同。 谈到集合,它们是使用Hash-Table
。 这允许sets
执行成员资格测试,即与查找为O(n)
list
相比,在O(1)
中进行查找。 因此,当in
一组进行, __contains__
尝试计算hash
需要使用加以研究对象的__hash__
。 由于列表在python中不可用,因此会出现错误: TypeError: unhashable type: 'list'
。 如果您对列表执行相同操作,则不会出现任何错误,因为列表不会为成员资格测试计算哈希值。
简而言之,不能对具有不可用对象的集合执行成员资格测试。 一般来说,所有可变对象(list, sets, dict)
都是不可删除的。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.