为什么以及何时在Python中使用像==这样的文字比较运算符在内置函数上使用自定义类型的魔术方法?

问题描述 投票:1回答:1

docs.python.org page on the Python "Data Model" states,当在文字比较操作中双方实现该操作的魔术方法时,[左操作数的方法与右操作数一起使用作为其参数:

[x<y呼叫x.__lt__(y)x<=y呼叫x.__le__(y)x==y呼叫x.__eq__(y)x!=y呼叫x.__ne__(y)x>y呼叫x.__gt__(y)x>=y呼叫x.__ge__(y)

下面的类包装了builtin tuple,并为这些比较运算符之一实现了一种魔术方法,以证明这一点:

class eqtest(tuple):
 def __eq__(self, other):
  print('Equivalence!')

当在比较运算符的左侧使用此类的实例时,它的行为符合预期:

>>> eqtest((1,2,3)) == (1,2,3)
Equivalence!

但是,即使仅使用右侧的实例,自定义类的比较运算符似乎也会被调用:

>>> (1,2,3) == eqtest((1,2,3))
Equivalence!

当显式调用左操作数的魔术方法时,结果也明显不同:

>>> (1,2,3).__eq__(eqtest2((1,2,3)))
True

很容易理解为什么这可能是一个有意的设计选择,尤其是对于子类而言,以便从以后定义的类型返回最有可能有用的结果。但是,由于它明显偏离了基本记录的行为,因此很难知道它如何以及为什么如此自信地工作,以说明并在生产中使用它。

在什么情况下,即使双方都提供了有效的结果,Python语言和CPython参考实现也会颠倒比较运算符的顺序,并且在哪里记录了此?

python cpython comparison-operators magic-methods
1个回答
0
投票

comparisons上的规则指出,元组不知道如何与其他类型进行比较。 tuplerichcompare执行Py_RETURN_NOTIMPLEMENTED。但是,PyObject richcompare检查子类型,例如继承的类,并交换比较顺序(应用对称规则)。

这也记录在您链接的页面中:

如果操作数是不同类型,并且右操作数的类型是左操作数类型的直接或间接子类,则右操作数的反射方法具有优先权,否则左操作数的方法具有优先权。不考虑虚拟子类化。

这使子类可以实现更特定的行为,这些行为可以使用两种方式编写的比较。

© www.soinside.com 2019 - 2024. All rights reserved.