[英]What happens "behind the scenes" if I call `None == x` in Python?
我正在學習和玩弄 Python,我想出了以下測試代碼(請注意,我不會編寫那樣的高效代碼,但在學習新語言時,我喜歡玩弄該語言的極端情況):
a = None
print(None == a) # I expected True, I got True
b = 1
print(None == b) # I expected False, I got False
class MyNone:
# Called if I compare some myMyNone == somethingElse
def __eq__(self, __o: object) -> bool:
return True
c = MyNone()
print (None == c) # !!! I expected False, I got True !!!
請查看代碼示例的最后一行。
None == something
怎么可能返回True
,而 something 顯然不是None
? 我本來期望something == None
的結果,但不是None == something
的結果。
我預計它會調用None is something
。
所以我認為問題歸結為: None
單例對象的__eq__
方法是什么樣子的,我怎么能找到它呢?
PS:我知道PEP-0008及其引用
與像 None 這樣的單例比較應該總是用 is 或 is not 來完成,永遠不要用相等運算符。
但我仍然想知道為什么上面示例中的print (None == c)
返回True
。
如文檔中所述: x==y
調用x.__eq__(y)
,但是None.__eq__(...)
返回NotImplemented
除了None
本身之外的任何東西(缺失部分:為什么?我不知道),所以 Python嘗試以另一種方式進行比較,並從始終返回True
的MyNone
調用__eq__
。
更新: None
( NoneType
類)沒有定義自己的__eq__
並使用基於is
測試的默認object.__eq__
:如果參數相同is
返回True
,否則返回NotImplemented
。 (感謝共同作者)
事實上, None
的類型沒有自己的__eq__
方法; 在 Python 中我們可以看到它顯然繼承自基類object
:
>>> type(None).__eq__
<slot wrapper '__eq__' of 'object' objects>
但這並不是源代碼中真正發生的事情。 None
的實現可以在 CPython 源碼中的Objects/object.c
中找到,我們看到:
PyTypeObject _PyNone_Type = {
PyVarObject_HEAD_INIT(&PyType_Type, 0)
"NoneType",
0,
0,
none_dealloc, /*tp_dealloc*/ /*never called*/
0, /*tp_vectorcall_offset*/
0, /*tp_getattr*/
0, /*tp_setattr*/
// ...
0, /*tp_richcompare */
// ...
0, /*tp_init */
0, /*tp_alloc */
none_new, /*tp_new */
};
我省略了大部分不相關的部分。 這里重要的是_PyNone_Type
的tp_richcompare
是0
,即空指針。 這是在do_richcompare
函數中檢查的:
if ((f = Py_TYPE(v)->tp_richcompare) != NULL) {
res = (*f)(v, w, op);
if (res != Py_NotImplemented)
return res;
Py_DECREF(res);
}
if (!checked_reverse_op && (f = Py_TYPE(w)->tp_richcompare) != NULL) {
res = (*f)(w, v, _Py_SwappedOp[op]);
if (res != Py_NotImplemented)
return res;
Py_DECREF(res);
}
為不會說 C 的人翻譯:
tp_richcompare
函數不為空,則調用它,如果其結果不是NotImplemented
,則返回該結果。tp_richcompare
函數不為空,則調用它,如果結果不是NotImplemented
,則返回該結果。 代碼中還有一些其他分支,以防這些分支都沒有返回結果。 但是這兩個分支足以看出是怎么回事了。 不是type(None).__eq__
返回NotImplemented
,而是該類型在 C 源代碼中根本沒有相應的函數。 這意味着第二個分支被采用,因此您觀察到的結果。
*如果已經檢查了反向,則設置標志checked_reverse_op
; 如果右側是左側的嚴格子類型,則會發生這種情況,在這種情況下它優先。 這在這種情況下不適用,因為type(None)
和您的類之間沒有子類型關系。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.