【问题标题】:Comparison operators vs “rich comparison” methods in PythonPython 中的比较运算符与“丰富的比较”方法
【发布时间】:2018-05-27 14:21:12
【问题描述】:

谁能解释一下两者之间的区别。那些通常是等效的吗?也许我在这里完全错了,但我认为每个比较运算符都必然与一个“丰富的比较”方法相关。这是来自文档:

操作符和方法名的对应关系为 如下:

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),和@98 @。

这是一个说明我的困惑的例子。

Python 3.x:

dict1 = {1:1}
dict2 = {2:2}

>>> dict1 < dict2
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: '<' not supported between instances of 'dict' and 'dict'
>>> dict1.__lt__(dict2)
NotImplemented

Python 2.x:

dict1 = {1:1}
dict2 = {2:2}

>>> dict1 < dict2
True
>>> dict1.__lt__(dict2)
NotImplemented

从 python 3 示例来看,似乎不支持调用 dict1 &lt; dict2 的逻辑。但是 Python 2 的例子呢?为什么会被接受?

我知道,与 Python 2 不同,在 Python 3 中,并非所有对象都支持比较运算符。但令我惊讶的是,两个版本在调用 __lt__() 时都会返回 NotImplemented 单例。

【问题讨论】:

  • 转念一想,我误读了。将重新开放。
  • @cᴏʟᴅsᴘᴇᴇᴅ 嗯,这个问题与我的问题有很大不同。它没有解释两者之间的区别,也没有提供关于何时返回 NotImplemented 的任何见解......
  • 我还觉得有趣的是&lt;__lt__ 不返回相同的结果。他们应该是因为&lt;调用__lt__,对吧?
  • @Ev.Kounis 是的,这是我的困惑。我总是理所当然地认为两者几乎基本相同。你能确认它确实没有返回同样的东西吗?也许是代码问题?
  • @scharette 我可以。用 Python 3.6.1 尝试过。我们需要等待这方面的大炮。

标签: python python-3.x python-2.7 comparison-operators


【解决方案1】:

这依赖于 __cmp__ 魔术方法,这是富比较运算符要取代的:

>>> dict1 = {1:1}
>>> dict2 = {2:2}
>>> dict1.__cmp__
<method-wrapper '__cmp__' of dict object at 0x10f075398>
>>> dict1.__cmp__(dict2)
-1

至于排序逻辑,这里是 Python 2.7 documentation:

映射(dict的实例)比较相等当且仅当它们有 相等的(键,值)对。键和值的平等比较 强制自反性。

平等以外的结果得到一致解决,但不是 另有定义。

带脚注:

早期版本的 Python 使用排序的字典比较 (key, value) 列表,但这对于常见的情况来说是非常昂贵的 比较平等。一个更早版本的 Python 比较 仅按身份的字典,但这引起了意外,因为 人们期望能够通过以下方式测试字典的空虚 将其与 {} 进行比较。

而且,在 Python 3.0 中,排序得到了简化。这是来自documentation

排序比较运算符 (&lt;, &lt;=, &gt;=, &gt;) 引发 TypeError 当操作数没有有意义的自然顺序时出现异常。

builtin.sorted()list.sort() 不再接受 cmp 参数 提供比较功能。请改用 key 参数。

cmp() 函数应该被视为消失,__cmp__() 特殊方法 不再支持。使用__lt__() 进行排序,__eq__()__hash__(),并根据需要进行其他丰富的比较。 (如果您确实需要 cmp() 功能,您可以使用表达式 (a &gt; b) - (a &lt;&gt; b) 作为 cmp(a, b) 的等效项。)

因此,明确地说,在 Python 2 中,由于未实现丰富的比较运算符,dict 对象将从数据模型 documentation 回退到 __cmp__

object.__cmp__(self, other)
富时由比较操作调用 比较(见上文)未定义。应该返回负数 如果 self 其他。

【讨论】:

  • 感谢您的回答,但似乎没有回答我的上述问题。也许是因为我不明白,如果是,我很抱歉。我仍然不明白为什么两个实现都没有返回相同的值。很明显,当将两个对象与&lt; 进行比较时,会调用__lt__()。在我的示例中显然不是这种情况。
  • @scharette 是的,正如解释的那样,在 Python 2 中,如果没有定义丰富的比较运算符,__cmp__ 是一个后备。您的误解是 &lt; 始终与 __lt__() 相关联,这在 Python 2 中不是这种情况,因为它仍然支持旧的 __cmp__ 方法,dict 对象 did使用
  • 好的,所以对于 dict,__lt__ 即使在 python 2 中也没有定义?
  • 是的,我只是很困惑为什么 Python 2 和 Python 3 没有产生相同的输出。但据我现在了解,__cmp__ 不再在 Python 3 中使用。
  • 只是一个建议,我会根据这个link指定python 3中的排序已经改变了非常感谢你带我去那里。
【解决方案2】:

运算符&lt;__lt__ 的注意事项:

import types

class A:
    def __lt__(self, other): return True

def new_lt(self, other): return False

a = A()
print(a < a, a.__lt__(a))  # True True
a.__lt__ = types.MethodType(new_lt, a)
print(a < a, a.__lt__(a))  # True False
A.__lt__ = types.MethodType(new_lt, A)
print(a < a, a.__lt__(a))  # False False

&lt; 调用类上定义的__lt____lt__ 调用在对象上定义的 __lt__

通常是一样的 :) 而且使用起来非常美味:A.__lt__ = new_lt

【讨论】:

    猜你喜欢
    • 2014-05-09
    • 2012-06-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-11-20
    • 2021-10-02
    • 2022-06-18
    • 2019-12-29
    相关资源
    最近更新 更多