簡體   English   中英

如果我在 Python 中調用“None == x”,“幕后”會發生什么?

[英]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嘗試以另一種方式進行比較,並從始終返回TrueMyNone調用__eq__

更新: NoneNoneType類)沒有定義自己的__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_Typetp_richcompare0 ,即空指針。 這是在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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM