PyP*_*rog 76 python comparison user-defined
由于Python不提供其比较运算符的左/右版本,它如何决定调用哪个函数?
class A(object):
def __eq__(self, other):
print "A __eq__ called"
return self.value == other
class B(object):
def __eq__(self, other):
print "B __eq__ called"
return self.value == other
>>> a = A()
>>> a.value = 3
>>> b = B()
>>> b.value = 4
>>> a == b
"A __eq__ called"
"B __eq__ called"
False
Run Code Online (Sandbox Code Playgroud)
这似乎称为两种__eq__
功能.只是寻找官方的决策树.
Ned*_*der 97
的a == b
表达调用A.__eq__
,因为它的存在.其代码包括self.value == other
.由于int不知道如何将自己与B进行比较,因此Python会尝试调用B.__eq__
以查看它是否知道如何将自身与int进行比较.
如果您修改代码以显示正在比较的值:
class A(object):
def __eq__(self, other):
print("A __eq__ called: %r == %r ?" % (self, other))
return self.value == other
class B(object):
def __eq__(self, other):
print("B __eq__ called: %r == %r ?" % (self, other))
return self.value == other
a = A()
a.value = 3
b = B()
b.value = 4
a == b
Run Code Online (Sandbox Code Playgroud)
它将打印:
A __eq__ called: <__main__.A object at 0x013BA070> == <__main__.B object at 0x013BA090> ?
B __eq__ called: <__main__.B object at 0x013BA090> == 3 ?
Run Code Online (Sandbox Code Playgroud)
kev*_*kev 56
当Python2.x看到时a == b
,它会尝试以下操作.
type(b)
是一个新式类,并且type(b)
是一个子类type(a)
,并且type(b)
已被覆盖__eq__
,那么结果就是b.__eq__(a)
.type(a)
已覆盖__eq__
(即type(a).__eq__
不是object.__eq__
),则结果为a.__eq__(b)
.type(b)
已被覆盖__eq__
,则结果为b.__eq__(a)
.__cmp__
.如果存在,则返回时对象是相等的zero
.object.__eq__(a, b)
,它是True
iff a
并且b
是同一个对象.如果任何特殊方法返回NotImplemented
,Python就好像该方法不存在一样.
请注意最后一步:如果既不是a
也不b
重载==
,那么a == b
就是相同的a is b
.
来自https://eev.ee/blog/2012/03/24/python-faq-equality/
Aar*_*all 21
__eq__
在 Python 中如何处理以及以什么顺序处理?Run Code Online (Sandbox Code Playgroud)a == b
人们通常理解,但并非总是如此,a == b
调用a.__eq__(b)
, 或type(a).__eq__(a, b)
。
明确地,评估的顺序是:
b
的类型是 的类型的严格子类(不是同一类型)a
并且具有__eq__
,则调用它并在实现比较时返回值,a
有__eq__
,则调用它并在实现比较时返回它,__eq__
并且它有它,然后如果实现了比较则调用并返回它,is
。如果方法返回 ,我们知道是否未实现比较NotImplemented
。
(在 Python 2 中,有一个__cmp__
被寻找的方法,但它在 Python 3 中被弃用并删除了。)
让我们通过让 B 子类化 A 来为自己测试第一个检查的行为,这表明接受的答案在这个计数上是错误的:
a == b
Run Code Online (Sandbox Code Playgroud)
仅B __eq__ called
在返回之前打印False
。
此处的其他答案似乎不完整且已过时,因此我将更新信息并向您展示如何自己查找。
这是在 C 级别处理的。
我们需要在这里查看两个不同的代码位 - __eq__
class 对象的默认值object
,以及查找和调用该__eq__
方法的代码,无论它是使用默认值__eq__
还是自定义方法。
__eq__
__eq__
在相关的 C api 文档中查找向我们展示了__eq__
由tp_richcompare
- 在"object"
类型定义中cpython/Objects/typeobject.c
定义的object_richcompare
for case Py_EQ:
。
case Py_EQ:
/* Return NotImplemented instead of False, so if two
objects are compared, both get a chance at the
comparison. See issue #1393. */
res = (self == other) ? Py_True : Py_NotImplemented;
Py_INCREF(res);
break;
Run Code Online (Sandbox Code Playgroud)
所以在这里,如果self == other
我们返回True
,否则我们返回NotImplemented
对象。这是任何未实现其自身__eq__
方法的对象子类的默认行为。
__eq__
被调用然后我们找到 C API 文档,即PyObject_RichCompare函数,它调用do_richcompare
.
然后我们看到tp_richcompare
为"object"
C 定义创建的函数被调用do_richcompare
,所以让我们更仔细地看一下。
此函数中的第一个检查是比较对象的条件:
__eq__
方法,然后用交换的参数调用另一个方法,如果实现则返回值。如果该方法没有实现,我们继续......
if (!Py_IS_TYPE(v, Py_TYPE(w)) &&
PyType_IsSubtype(Py_TYPE(w), Py_TYPE(v)) &&
(f = Py_TYPE(w)->tp_richcompare) != NULL) {
checked_reverse_op = 1;
res = (*f)(w, v, _Py_SwappedOp[op]);
if (res != Py_NotImplemented)
return res;
Py_DECREF(res);
Run Code Online (Sandbox Code Playgroud)
接下来我们看看是否可以__eq__
从第一种类型中查找方法并调用它。只要结果不是NotImplemented,即实现了,我们就返回它。
if ((f = Py_TYPE(v)->tp_richcompare) != NULL) {
res = (*f)(v, w, op);
if (res != Py_NotImplemented)
return res;
Py_DECREF(res);
Run Code Online (Sandbox Code Playgroud)
否则如果我们没有尝试其他类型的方法并且它在那里,我们然后尝试它,如果实现了比较,我们返回它。
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)
最后,我们得到一个回退,以防它没有为任何一个类型实现。
回退检查对象的身份,即它是否是内存中同一位置的同一对象 - 这与 for 的检查相同self is other
:
/* If neither object implements it, provide a sensible default
for == and !=, but raise an exception for ordering. */
switch (op) {
case Py_EQ:
res = (v == w) ? Py_True : Py_False;
break;
Run Code Online (Sandbox Code Playgroud)
在比较中,我们首先尊重比较的子类实现。
然后我们尝试与第一个对象的实现进行比较,然后与第二个对象的实现进行比较,如果它没有被调用。
最后,我们使用身份测试来比较相等性。
归档时间: |
|
查看次数: |
93837 次 |
最近记录: |