提问人:Markus Weninger 提问时间:12/9/2022 最后编辑:Markus Weninger 更新时间:12/18/2022 访问量:295
如果我在 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
None
True
something == None
None == something
我以为它会在幕后打电话。None is something
所以我认为问题归结为:None
单例对象的 __eq__
方法是什么样子的,我怎么能找到它?
PS:我知道PEP-0008及其报价
与像 None 这样的单例进行比较时,应始终使用 is 或 is not,而不是相等运算符。
但我仍然想知道为什么在上面的例子中返回.print (None == c)
True
答:
如文档中所述:调用,但返回除本身以外的任何内容(缺少部分:为什么?我不知道),所以 Python 尝试以相反的方式进行比较,并从 which 总是返回 .x==y
x.__eq__(y)
None.__eq__(...)
NotImplemented
None
__eq__
MyNone
True
Update:(类)不定义自己的,而是使用基于测试的默认值:如果参数相同或其他,则返回。(感谢合著者)None
NoneType
__eq__
object.__eq__
is
True
is
NotImplemented
评论
NotImplemented
raised from 的意思与它不存在的意思相同,这允许解释器回退到右侧检查。__eq__
NotImplemented
type(None).__eq__
object.__eq__
True
__eq__
__eq__
NotImplemented
__eq__
None
NotImplemented
__eq__
NotImplemented
__eq__
__eq__
True
False
float.__eq__(1.0, 1)
float.__eq__(1.0, 2)
NotImplemented
__eq__
__eq__
其实,的类型并没有自己的方法;在 Python 中,我们可以看到它显然是从基类继承的:None
__eq__
object
>>> type(None).__eq__
<slot wrapper '__eq__' of 'object' objects>
但这并不是源代码中真正发生的事情。的实现可以在 CPython 源代码的 Objects/object.c
中找到,我们看到:None
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 */
};
我省略了大部分不相关的部分。这里重要的是 's 是 ,即一个空指针。这在 do_richcompare
函数中检查:_PyNone_Type
tp_richcompare
0
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 语言的人翻译:
- 如果左侧的函数不为 null,则调用它,如果其结果不是,则返回该结果。
tp_richcompare
NotImplemented
- 否则,如果尚未检查反向*,并且右侧的函数不为 null,则调用它,如果结果不是,则返回该结果。
tp_richcompare
NotImplemented
代码中还有一些其他分支,如果这些分支都没有返回结果,则可以回退到这些分支。但这两个分支足以看出发生了什么。不是返回,而是该类型在C源代码中根本没有相应的函数。这意味着第二个分支被占用,因此您观察到的结果。type(None).__eq__
NotImplemented
*如果已经检查了反向,则设置了标志checked_reverse_op
;如果右侧是左侧的严格子类型,则会发生这种情况,在这种情况下,它优先。这不适用于这种情况,因为 type(None)
和您的类之间没有子类型关系。
评论
object.__eq__
type(None).__eq__
==
__eq__
tp_richcompare
__eq__
object
object
__eq__
object.c
object
tp_richcompare
__eq__
==
object
do_richcompare
tp_richcompare
==
!=
TypeError
评论
eq
c == None
c == None
__eq__
None == c
__eq__
method of the None singleton object” - 你为什么不试试呢?