【问题标题】:Why is `int.__eq__(other)` a working comparison?为什么 `int.__eq__(other)` 是一个有效的比较?
【发布时间】:2016-12-09 12:23:46
【问题描述】:

以下代码适用于 Python 2.7:

>>> class Derived(int):
...     def __eq__(self, other):
...         return int.__eq__(other)
...
>>> Derived(12) == 12.0
True
>>> Derived(12) == 13
False

鉴于self 属性未明确赋予int.__eq__() 方法调用,我不明白它为什么起作用。

[编辑]

到目前为止的答案表明,它是关于通过self.__eq__(other) 返回NotImplemented 并因此调用other.__eq__(self)。然后Derived(12) == Derived(12)我期望是不定式递归,其实不然:

>>> Derived(12) == Derived(12)
True

【问题讨论】:

    标签: python python-2.7


    【解决方案1】:

    之所以有效,是因为int.__eq__(<something>) 返回NotImplemented,发生这种情况时会调用other.__eq__(self),这就是这里返回TrueFalse 的原因。

    演示:

    class Derived(int):
         def __eq__(self, other):
             print self, other
             print int.__eq__(other)
             print other.__eq__(self)
             return int.__eq__(other)
    
    >>> Derived(12) == 12.0
    12 12.0
    NotImplemented
    True
    True
    >>> Derived(12) == 13.0
    12 13.0
    NotImplemented
    False
    False
    

    来自NotImplemented 的文档:

    二进制特殊方法应返回的特殊值 (例如__eq__()__lt__()__add__()__rsub__() 等)到 表示该操作未针对 其他类型;可以由就地二进制特殊方法返回 (例如__imul__()__iand__() 等)用于相同目的。它的 真值是真的。

    注意当NotImplemented 返回时,解释器会尝试 其他类型的反射操作,或其他一些回退, 取决于运营商。如果所有尝试的操作都返回 NotImplemented,解释器将引发适当的异常。


    __eq__ 都返回NotImplemented 时会发生什么?

    Python 2 和 3 中的行为不同。

    在 Python 2 中,它首先回退到 __cmp__ 方法,整数具有 __cmp__ method in Python 2。它已在 Python 3 中删除。

    根据 Python 2 文档,如果没有找到任何东西,它最终会退回到身份比较:

    如果没有定义__cmp__()__eq__()__ne__()操作,类 实例按对象标识(“地址”)进行比较

    class Derived(int):
        def __eq__(self, other):
            print ("Inside  __eq__")
            return NotImplemented
    
        def __cmp__(self, other):
            print ("Inside __cmp__ finally")
            return True
    
    >>> Derived(12) == Derived(12)
    Inside  __eq__
    Inside  __eq__
    Inside __cmp__ finally
    False
    

    不要定义一个没有定义方法的类:

    class Derived(object):
        pass
    
    >>> Derived() == Derived()  
    False
    >>> d = Derived()
    >>> d == d  # Same objects.
    True
    

    Python 3 不再有 __cmp__ 方法,但它现在似乎正在回归身份。而且似乎也没有记录。

    #  Python 3.5
    >>> Derived() == Derived()
    False
    >>> d = Derived()
    >>> d == d
    True
    

    【讨论】:

      【解决方案2】:

      【讨论】:

      • 哦,来吧,12 甚至没有溢出半精度浮点数。它可以完美地转换为双精度。
      【解决方案3】:

      在 Python 2.7 中,如果您调用 int.__eq__,它总是返回 NotImplemented。示例:

      >>> int.__eq__(12.0)
      NotImplemented
      

      当您使用== 运算符时,它将尝试在左侧参数上运行__eq__ 方法,如果它得到NotImplemented,它将从右侧参数返回__eq__ 方法的结果.

      Derived(12) == 12.0 的示例中,解释器首先尝试Derived(12).__eq__(12.0),然后得到NotImplemented。然后它在float 号码12.0 上运行__eq__ 方法并获得True

      在您的 Derived(12) == Derived(12) 示例中,可能发生的情况是,由于两个对象都为它们的 __eq__ 方法返回 NotImplemented,并且由于 Derived 继承自 int,因此解释器回退到使用cmp int 的内置行为(根据 this answer,链接到您问题的另一个答案)。

      这里有一个例子来说明你的情况:

      class Derived(int):
          def __eq__(self, other):
              print 'Doing eq'
              return NotImplemented
          def __cmp__(self, other):
              print 'doing cmp'
              return 0  # contrived example - don't do this
      
      >>> Derived(12) == Derived(12)
      doing eq
      doing eq
      doing cmp
      True
      

      【讨论】:

      • 编辑考虑了int.__eq__的所有参数
      • 更新了问题以包含Derived(12) == Derived(12) case
      猜你喜欢
      • 1970-01-01
      • 2016-10-22
      • 1970-01-01
      • 1970-01-01
      • 2011-07-01
      • 2015-12-07
      • 1970-01-01
      • 2021-04-02
      • 2010-11-05
      相关资源
      最近更新 更多