![](/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.