当前位置: 首页 > 面试题库 >

为什么/何时在Python中`x == y`调用`y .__ eq __(x)`?

欧浩淼
2023-03-14
问题内容

Python文档明确指出了x==y调用x.__eq__(y)。但是似乎在许多情况下,情况恰恰相反。它何时何地发生的原因在哪里记录,如何确定我的对象__cmp____eq__方法将被调用。

编辑:只是为了澄清,我知道__eq__在优选中调用__cmp__,但是我不清楚为什么y.__eq__(x)优先于调用x.__eq__(y),而后者是文档状态将发生的原因。

>>> 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

编辑:从马克·迪金森的答案和评论中,它看起来像是:

  1. 丰富的比较替代 __cmp__
  2. __eq__是它自己的__rop__,以它的__op__(以及类似的__lt____ge__等等)
  3. 如果左对象是内置类或新样式类,而右对象是其子类,则__rop__在左对象之前尝试右对象__op__

这解释了TestStrCmp示例中的行为。
TestStrCmp是的子类,str但没有实现自己的子类,__eq__因此两种情况下__eq__ofstr优先(例如,由于规则1而tsc == "b"调用)。b.__eq__(tsc)``__rop__

TestStrEq示例中,tse.__eq__在两种情况下都被调用,因为它TestStrEq是的子类,str因此优先调用它。

TestEq示例中,两次TestEq实现(__eq__int不是__eq__两次)都被调用(规则1)。

但我仍然不了解的第一个示例TestCmptc不是intAFAICT的子类,因此1.__cmp__(tc)应该调用AFAICT ,但不是。


问题答案:

您缺少通常行为的关键例外:当右侧操作数是左侧操作数类的子类的实例时,将首先调用右侧操作数的特殊方法。

请参阅以下文档:

http://docs.python.org/reference/datamodel.html#coercion-
rules

特别是以下两段:

对于xy,首先 x.__op__(y)尝试。如果未实现或返回
NotImplemented,请y.__rop__(x)尝试。如果这也没有实现或返回NotImplemented,则引发TypeError异常。但是请参见以下异常:

上一项的例外:如果左操作数是内置类型或新样式类的实例,而右操作数是该类型或类的适当子类的实例,并且覆盖基数的
__rop__()方法,则右操作的__rop__()方法是左操作的尝试过__op__() 的方法。



 类似资料:
  • 问题内容: 考虑以下示例: 我不确定Java语言规范中是否有一项规定要加载变量的先前值以便与右侧()进行比较,该变量应按照方括号内的顺序进行计算。 为什么第一个表达式求值,而第二个表达式求值?我本来希望先被评估,然后再与自身()比较并返回。 这个问题与Java表达式中子表达式的求值顺序不同,因为这里绝对不是“子表达式”。需要 加载 它以进行比较,而不是对其进行“评估”。这个问题是特定于Java的,

  • 这个问题与Java表达式中子表达式的求值顺序不同,因为在这里肯定不是“子表达式”。需要加载它进行比较,而不是“求值”。这个问题是特定于Java的,表达式来自一个真实的项目,而不是通常为棘手的面试问题而设计的牵强附会的不切实际的构造。它应该是比较和替换习语的一行替换 它比x86 CMPXCHG指令还要简单,因此在Java中应该使用更短的表达式。

  • 问题内容: 我期望值可以交换。但是它给出x = 0和y = 1。当我尝试使用C语言时,它会给出正确的结果。 问题答案: 您的陈述大致相当于这种扩展形式: 与C语言不同,在Java中,保证二进制运算符的左操作数在右操作数之前进行求值。评估如下: 您可以反转每个xor表达式的参数顺序,以便在再次评估变量之前完成赋值: 这是一个更紧凑的版本,也可以使用: 但这是交换两个变量的真正可怕的方法。使用临时变量

  • Python(x,y) 是一个免费的科学和工程开发包,提供数学计算、数据分析和可视化展示。   

  • 问题内容: 几年前我有这个面试问题,但是我还没有找到答案。 做无限循环的x和y应该是什么? 我们试着用,, VS 。 问题答案: 您需要两个可比较,具有相同值但代表不同实例的变量,例如: 和都为true,因为取消了装箱,但是实例相等性为false。 请注意,它也可以与一起使用,并且任何值(不仅是0)都可以使用。 您还可以使用JVM的复杂性-它们通常仅缓存最多127个整数,因此也可以使用: (但是1

  • 问题内容: 好的,我喜欢Python的功能。一直使用它,非常棒。我时不时地想做相反的事情,想想“我曾经知道怎么做”,然后用google python解压缩,然后记住,有人用这种魔术来解压缩一个元组的压缩列表。像这样: 到底是怎么回事?那神奇的星号在做什么?它还能在其他地方应用?Python中还有哪些其他令人赞叹的令人敬畏的事物如此神秘且难以谷歌搜索? 问题答案: Python教程中的解压缩参数列表