比较运算符与Python中的“丰富比较”方法

时间:2017-12-13 15:59:47

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

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

  

运算符符号和方法名称之间的对应关系为   如下:

     

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)

这是一个展示我困惑的例子。

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 < dict2的逻辑。但是Python 2的例子呢?为什么会被接受?

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

2 个答案:

答案 0 :(得分:8)

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

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

关于排序 logic ,这里是Python 2.7 documentation

  

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

     

除了平等以外的结果会得到一致的解决,但事实并非如此   否则定义。

用脚注:

  

早期版本的Python使用了排序的词典比较   (键,值)列表,但这对于常见的情况非常昂贵   比较平等。比较早期的Python版本   只有身份的词典,但这引起了惊喜,因为   人们期望能够通过测试字典的空虚   将它与{}进行比较。

而且,在Python 3.0中,订购已经简化。这来自documentation

  

排序比较运算符(<, <=, >=, >)引发TypeError   操作数没有有意义的自然顺序时的异常。

     

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

     

cmp()函数应视为已消失,__cmp__()特殊方法   不再受支持。使用__lt__()进行排序,__eq__()   __hash__(),以及其他必要的丰富比较。 (如果您确实需要cmp()功能,则可以使用(a > b) - (a <> b)表达式作为cmp(a, b)的等效项。)

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

  

object.__cmp__(self, other)
  如果丰富,则通过比较操作调用   比较(见上文)未定义。应该返回负数   整数,如果自己&lt;其他,零如果自我==其他,正整数   如果自己&gt;其他

答案 1 :(得分:1)

操作员<__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__

它通常是相同的:)使用它是完全可口的:A.__lt__ = new_lt