Mar*_*ger 9 python equality comparison-operators python-3.x nonetype
我正在学习和使用 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 !!!
Run Code Online (Sandbox Code Playgroud)
请参阅代码示例的最后一行。
None == something明明不存在的东西怎么会None返回True呢?我本希望得到这样的结果something == None,但不是None == something。
我预计它会None is something在幕后调用。
所以我认为问题归结为:单例对象的方法是什么样的以及我如何找到它?__eq__None
PS:我知道PEP-0008及其报价
与像 None 这样的单例的比较应该总是使用 is 或 is not 来完成,而不是使用相等运算符。
但我仍然想知道为什么print (None == c)在上面的例子中返回True.
事实上,None的类型没有自己的__eq__方法;在Python中我们可以看到它显然继承自基类object:
>>> type(None).__eq__
<slot wrapper '__eq__' of 'object' objects>
Run Code Online (Sandbox Code Playgroud)
但这并不是源代码中真正发生的事情。的实现可以在 CPython 源代码中None找到,我们可以看到: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 */
};
Run Code Online (Sandbox Code Playgroud)
我省略了大部分不相关的部分。这里重要的是_PyNone_Types tp_richcompareis 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);
}
Run Code Online (Sandbox Code Playgroud)
为不会说 C 的人翻译:
tp_richcompare函数不为空,则调用它,如果其结果不为空,NotImplemented则返回该结果。tp_richcompare函数不为空,则调用它,如果结果不是,NotImplemented则返回该结果。代码中还有一些其他分支,以防万一这些分支都没有返回结果。但这两个分支足以看出发生了什么。并不是type(None).__eq__return NotImplemented,而是该类型在 C 源代码中根本没有相应的函数。这意味着采用了第二个分支,因此是您观察到的结果。
checked_reverse_op*如果已经检查了反向方向,则设置该标志;如果右侧是左侧的严格子类型,则会发生这种情况,在这种情况下它优先。type(None)这不适用于这种情况,因为您的类之间没有子类型关系。
正如文档中所述:x==y调用x.__eq__(y),但None.__eq__(...)返回除自身NotImplemented之外的任何内容None(缺少部分:为什么?我不知道),因此 Python 尝试以相反的方式进行比较,并__eq__从MyNone始终返回的中调用True。
更新:(None类NoneType)没有定义自己的并使用基于测试的__eq__默认值:如果参数相同或不同,则返回。(感谢共同作者)object.__eq__isTrueisNotImplemented
| 归档时间: |
|
| 查看次数: |
319 次 |
| 最近记录: |