为什么/何时在Python中,`x==y`调用`y.\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\?

为什么/何时在Python中,`x==y`调用`y.\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\?,python,comparison,operator-overloading,Python,Comparison,Operator Overloading,Python文档清楚地声明x==y调用x.\uuuueq\uuuuy(y)。然而,在许多情况下,情况似乎恰恰相反。在何处记录了发生这种情况的时间或原因,以及如何确定对象的\uuuucmp\uuuuuuu或\uuuuuuu eq\uuuuu方法是否将被调用 编辑:我只是想澄清一下,我知道调用\uuuuuueq\uuuuuu比调用\uuuucmp\uuuuuuuu更优先,但我不清楚为什么y.\uuuuuueq\uuuuuuuuuuuuuuuux比调用x.\uuuuuuuuuueq\uuuuuuuuu

Python文档清楚地声明
x==y
调用
x.\uuuueq\uuuuy(y)
。然而,在许多情况下,情况似乎恰恰相反。在何处记录了发生这种情况的时间或原因,以及如何确定对象的
\uuuucmp\uuuuuuu
\uuuuuuu eq\uuuuu
方法是否将被调用

编辑:我只是想澄清一下,我知道调用
\uuuuuueq\uuuuuu
比调用
\uuuucmp\uuuuuuuu
更优先,但我不清楚为什么
y.\uuuuuueq\uuuuuuuuuuuuuuuux
比调用
x.\uuuuuuuuuueq\uuuuuuuuuuuuuy
更优先,而文档状态就是后者

>>> class TestCmp(object):
...     def __cmp__(self, other):
...         print "__cmp__ got called"
...         return 0
... 
>>> class TestEq(object):
...     def __eq__(self, other):
...         print "__eq__ got called"
...         return True
... 
>>> tc = TestCmp()
>>> te = TestEq()
>>> 
>>> 1 == tc
__cmp__ got called
True
>>> tc == 1
__cmp__ got called
True
>>> 
>>> 1 == te
__eq__ got called
True
>>> te == 1
__eq__ got called
True
>>> 
>>> class TestStrCmp(str):
...     def __new__(cls, value):
...         return str.__new__(cls, value)
...     
...     def __cmp__(self, other):
...         print "__cmp__ got called"
...         return 0
... 
>>> class TestStrEq(str):
...     def __new__(cls, value):
...         return str.__new__(cls, value)
...     
...     def __eq__(self, other):
...         print "__eq__ got called"
...         return True
... 
>>> tsc = TestStrCmp("a")
>>> tse = TestStrEq("a")
>>> 
>>> "b" == tsc
False
>>> tsc == "b"
False
>>> 
>>> "b" == tse
__eq__ got called
True
>>> tse == "b"
__eq__ got called
True
编辑:从马克·迪金森的回答和评论来看:

  • 丰富比较覆盖
    \uuu cmp\uuuu
  • \uuuu eq\uuuuu
    是它自己的
    \uuuu rop\uuuuu
    (类似于
    \uu lt\uuuuuu
    \uu ge\uuuuuuu
    等)
  • 如果左侧对象是一个内置类或新样式类,而右侧是它的子类,则在左侧对象的
    \uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
    之前尝试右侧对象的
  • 这解释了
    TestStrCmp
    示例中的行为
    TestStrCmp
    str
    的一个子类,但没有实现自己的
    \uuuu eq\uuuu
    ,因此
    str
    \uuuu eq\uuuuuu
    在这两种情况下都优先(即
    tsc==“b”
    调用
    b.\uu eq\uuuuuu(tsc)
    作为
    \uuu rop\uuuu>因为规则1)

    TestStrEq
    示例中,
    tse.\uuuuu eq\uuuu
    在这两个实例中都被调用,因为
    TestStrEq
    str
    的子类,因此优先调用它

    TestEq
    示例中,
    TestEq
    实现了
    \uuuueq\uuuuu
    ,而
    int
    则不会同时调用
    \uuuuueq\uuuuu
    (规则1)


    但是我仍然不理解
    TestCmp
    的第一个示例
    tc
    不是
    int
    上的子类,因此AFAICT
    1。应该调用\uuuu cmp\uuuuu(tc)
    ,但不是。

    中是否没有记录这一点?只要快速看一下,当定义了
    \uuuuuueq\uuuu
    \uult\uuuu
    等时,似乎忽略了
    \uucmp\uuuuu
    。我的理解是,包括在父类上定义
    \uuuu eq\uuu
    的情况<代码>str.uuu eq_uuu
    已定义,因此将忽略其子类上的
    \uuuu cmp\uuuu
    <代码>对象。未定义\uuuu eq\uuuu
    等,因此其子类上的
    \uuuu cmp\uuuu
    将得到尊重

    针对澄清的问题:

    我知道
    \uuuu eq\uuuu
    被调用了 我更喜欢
    \uuu cmp\uuuu
    ,但我不是 清楚为什么
    y.。\uuuueq\uuuuux)
    在中被调用 当 后者是docs州将要做的事情 发生

    文档说
    x.。\uuuueq\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu。我不知道你为什么相信这里发生了一些不同的事情

    你对哪种情况特别感到困惑?我理解你只是对
    “b”==tsc
    tsc==“b”
    案例感到困惑,对吗?在这两种情况下,
    str.\uuuuuueq\uuuuuuu(一件事,另一件事)
    正在被调用。由于您没有重写TestStrCmp中的
    \uuuuuu eq\uuuuu
    方法,因此最终您只依赖于基本字符串方法,它表示对象不相等

    在不知道
    str.\uuuuu eq\uuuu
    的实现细节的情况下,我不知道
    (“b”)。\uuuuuu eq\uuuu(tsc)
    是否会返回
    NotImplemented
    ,并给tsc一个处理平等性测试的机会。但即使它这样做了,按照TestStrCmp的定义方式,您仍然会得到一个错误的结果

    所以不清楚你在这里看到了什么,这是出乎意料的

    也许现在的情况是,如果Python在被比较的对象上定义了
    \uuuuu eq\uuuu
    ,那么它更喜欢
    \uuuuu cmp\uuuuu
    ,而您希望最左侧对象上的
    \uuuu cmp\uuuuu
    优先于右侧对象上的
    \uuu eq\uu
    。是吗?

    据我所知,
    \uuuuuu eq\uuuuu()
    是一种所谓的“丰富比较”方法,与下面的
    \uuuu cmp\uuuuu()
    相比,它更适合于比较运算符<如果未定义“丰富比较”,则调用代码>\uuuu cmp\uuuu()

    所以在A==B:
    如果在中定义了
    \uuuuu eq\uuuu()
    ,则将调用
    否则将调用
    \uuu cmp\uuu()

    在'str'中定义了
    \uuuuu eq\uuuuuuuuuuuuuu()
    ,因此未调用您的
    \uuuuuuu cmp\uuuuuuuuuuuuu()
    函数

    同样的规则也适用于
    \uuu ne\uuuuuuu()、\ uuuu gt\uuuuuu()、\ uu ge\uuuuuuuuu()、\ uuuuuu lt\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu()
    \uuuuuuuuuuuuuu

    如果未定义富比较(见上文),则比较操作会调用[
    \uuu\cmp\uu


    \uuuuuu eq\uuuuu
    是一种丰富的比较方法,在
    TestCmp
    的情况下没有定义,因此调用
    \uuuuu cmp\uuuu
    您缺少一个常见行为的关键异常:当右侧操作数是左侧操作数类的子类的实例时,首先调用右操作数的特殊方法

    请参阅以下网址的文档:

    特别是以下两段:

    对于对象
    x
    y
    ,首先
    x.\uuuu op\uuuuu(y)
    已尝试。如果不是这样的话 执行或返回
    NotImplemented
    y.\uuuuu-rop\uuuuuuuux
    是 尝试如果这也没有实现 或返回
    未实现
    ,一个 引发TypeError异常。但是看到了吗 以下例外情况:

    前一项的例外情况:如果 左操作数是 内置类型或新样式的类, 右操作数是一个实例 适当的