Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/324.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python是如何处理eq的?顺序是什么?_Python_Comparison_User Defined - Fatal编程技术网

Python是如何处理eq的?顺序是什么?

Python是如何处理eq的?顺序是什么?,python,comparison,user-defined,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"

由于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
这似乎调用了两个
\uuuuu eq\uuu
函数


我正在寻找正式的决策树。

表达式调用
a.\uuu eq\uuuu
,因为它存在。其代码包括
self.value==other
。由于int不知道如何将自己与B进行比较,Python尝试调用
B.\uuu eq\uu
,看看它是否知道如何将自己与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
它将打印:

A __eq__ called: <__main__.A object at 0x013BA070> == <__main__.B object at 0x013BA090> ?
B __eq__ called: <__main__.B object at 0x013BA090> == 3 ?
A uuu eq_uuu_uu_uu_uu_uu_uu_u_u_u_u_u_u_u_u_u_u_u_?
B uuu eq uuuu调用:==3?

当Python2.x看到
a==b
时,它会尝试以下操作

  • 如果
    type(b)
    是一个新样式的类,
    type(b)
    type(a)
    的子类,并且
    type(b)
    已经覆盖了
    \uuueq\uuuu
    ,那么结果就是
    b.\uueq\uuuuu(a)
  • 如果
    type(a)
    已覆盖
    \uuuueq\uuuuuuuuu
    (也就是说,
    type(a)。\uuuuuuuueq\uuuuuu
    不是
    对象。\uuuuuuueq\uuuuuuuu
    ),则结果是
    a.\uuuuueq\uuuuuuuu(b)
  • 如果
    类型(b)
    已覆盖
    \uuuuueq\uuuu
    ,则结果为
    b.。\uuuuuueq\uuuuiq(a)
  • 如果上述情况都不是这样,Python将重复查找
    \uuuucmp\uuuu
    的过程。如果存在,当它返回
    零时,对象相等
  • 作为最后的回退,Python调用
    对象。
    True
    iff
    a
    b
    是同一个对象
如果任何一个特殊方法返回
NotImplemented
,Python就好像该方法不存在一样

请注意最后一步:如果
a
b
均未重载
=
,则
a==b
a是b
相同



中,我正在为Python 3编写关于这个问题的更新答案

Python是如何处理
\uuuuuuuueq\uuuuuuu
的,顺序是什么? 人们通常理解,但并不总是这样,即
a==b
调用
a.\uuuueq\uuuuuuuuuuuub
,或
类型(a)。\uuuuuueq\uuuuuuuuu(a,b)

明确地说,评估的顺序是:

  • 如果
    b
    的类型是
    a
    类型的严格子类(不同类型),并且有一个
    \uuuuuu eq\uuuu
    ,则调用它并返回值(如果实现了比较)
  • 否则,如果
    a
    具有
    \uuuuu eq\uuuuu
    ,则调用它并在执行比较时返回它
  • 否则,看看我们是否没有调用b的
    \uuuu eq\uuuu
    ,并且它有,然后如果实现了比较,则调用并返回它
  • 否则,最后,对标识进行比较,与
    的比较相同
  • 如果方法返回
    NotImplemented
    ,我们就知道比较是否没有实现

    (在Python2中,有一个
    \uu\cmp\uu
    方法被查找,但在Python3中被弃用并删除。)

    让我们通过让B子类A来测试第一个检查的行为,这表明接受的答案在这方面是错误的:

    A类:
    值=3
    定义(自身、其他):
    打印('A _; eq _; called')
    返回self.value==other.value
    B(A)类:
    值=4
    定义(自身、其他):
    打印('B _; eq _;调用')
    返回self.value==other.value
    a、 b=a(),b()
    a==b
    
    在返回
    False
    之前,仅打印调用的
    B\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu

    我们怎么知道这个完整的算法? 这里的其他答案似乎不完整且过时,因此我将更新这些信息,并向您展示如何自己查找这些信息

    这是在C级处理的

    这里我们需要看两个不同的代码位——类
    object
    的对象的默认
    \uuuuueq\uuuuu
    ,以及查找和调用
    \uuuuueq\uuuuu
    方法的代码,不管它是使用默认的
    \uuuuueq\uuuu
    方法还是自定义方法

    默认值
    \uuuu eq\uuuu
    查看中的
    \uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu

        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;
    
    因此,在这里,如果
    self==other
    我们返回
    True
    ,否则我们返回
    NotImplemented
    对象。这是对象的任何子类的默认行为,该子类不实现自己的
    \uuuuuueq\uuuuu
    方法

    如何调用
    \uuuu eq\uuuu
    然后我们找到C API文档,即调用
    do\u richcompare
    的函数

    然后我们看到为
    “object”
    C定义创建的
    tp\u richcompare
    函数被
    do\u richcompare
    调用,所以让我们更仔细地看一下

    此函数中的第一个检查用于比较对象的条件:

    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
    
    • 不是同一类型,但是
    • 第二个类型是第一个类型的子类,并且
    • 第二个类型有一个
      \uuuu eq\uuu
      方法
    然后使用交换的参数调用另一个的方法,如果实现,则返回值。如果该方法未实现,我们将继续

        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);
    
    接下来,我们看看是否可以从第一个类型中查找
    \uuuuueq\uuuu
    方法并调用它。 只要结果没有实现,也就是说,它已经实现,我们就返回它

        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);
        }
    
    否则,如果我们没有尝试另一种类型的方法,它就在那里,我们就尝试它,如果实现了比较,我们就返回它

        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);
        }
    
    最后,我们得到了一个后备方案,以防这两种类型都没有实现

    回退检查对象的标识,即它是否是内存中同一位置的同一对象-这与检查
    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;
    
    结论