Python 中的比较运算符与“丰富的比较"方法 [英] Comparison operators vs “rich comparison” methods in Python

查看:60
本文介绍了Python 中的比较运算符与“丰富的比较"方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

<块引用>

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

x 调用 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<字典2回溯(最近一次调用最后一次):文件<stdin>",第 1 行,位于 <module>类型错误:'<''dict' 和 'dict' 实例之间不支持>>>dict1.__lt__(dict2)未实现

Python 2.x:

dict1 = {1:1}dict2 = {2:2}>>>dict1<字典2真的>>>dict1.__lt__(dict2)未实现

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

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

解决方案

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

<预><代码>>>>dict1 = {1:1}>>>dict2 = {2:2}>>>dict1.__cmp__<0x10f075398 处 dict 对象的方法包装器__cmp__">>>>dict1.__cmp__(dict2)-1

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

<块引用>

映射(字典的实例)比较相等当且仅当它们有相等(键,值)对.键和值的相等比较强制反身性.

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

带脚注:

<块引用>

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

而且,在 Python 3.0 中,排序已得到简化.这是来自文档:

<块引用>

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

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

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

所以,明确地说,在 Python 2 中,由于没有实现丰富的比较运算符,dict 对象将从数据模型回退到 __cmp__文档:

<块引用>

object.__cmp__(self, other)
如果丰富,则由比较操作调用比较(见上文)未定义.应该返回负数整数,如果 self <其他,如果 self == other 为零,则为正整数如果自己 > 其他.

Can someone explain me the differences between the two. Are those normally equivalent ? Maybe I'm completely wrong here, but I thought that each comparison operator was necessarily related to one "rich comparison" method. This is from the documentation:

The correspondence between operator symbols and method names is as follows:

x<y calls x.__lt__(y), x<=y calls x.__le__(y), x==y calls x.__eq__(y), x!=y calls x.__ne__(y), x>y calls x.__gt__(y), and x>=y calls x.__ge__(y).

Here is an example that demonstrates my confusion.

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

From the python 3 example, it seems logic that calling dict1 < dict2 is not supported. But what about Python 2 example ? Why is it accepted ?

I know that unlike Python 2, in Python 3, not all objects supports comparison operators. At my surprise though, both version return the NotImplemented singleton when calling __lt__().

解决方案

This is relying on the __cmp__ magic method, which is what the rich-comparison operators were meant to replace:

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

As to the ordering logic, here is the Python 2.7 documentation:

Mappings (instances of dict) compare equal if and only if they have equal (key, value) pairs. Equality comparison of the keys and values enforces reflexivity.

Outcomes other than equality are resolved consistently, but are not otherwise defined.

With a footnote:

Earlier versions of Python used lexicographic comparison of the sorted (key, value) lists, but this was very expensive for the common case of comparing for equality. An even earlier version of Python compared dictionaries by identity only, but this caused surprises because people expected to be able to test a dictionary for emptiness by comparing it to {}.

And, in Python 3.0, ordering has been simplified. This is from the documentation:

The ordering comparison operators (<, <=, >=, >) raise a TypeError exception when the operands don’t have a meaningful natural ordering.

builtin.sorted() and list.sort() no longer accept the cmp argument providing a comparison function. Use the key argument instead.

The cmp() function should be treated as gone, and the __cmp__() special method is no longer supported. Use __lt__() for sorting, __eq__() with __hash__(), and other rich comparisons as needed. (If you really need the cmp() functionality, you could use the expression (a > b) - (a <> b) as the equivalent for cmp(a, b).)

So, to be explicit, in Python 2, since the rich comparison operators are not implemented, dict objects will fall-back to __cmp__, from the data-model documentation:

object.__cmp__(self, other)
Called by comparison operations if rich comparison (see above) is not defined. Should return a negative integer if self < other, zero if self == other, a positive integer if self > other.

这篇关于Python 中的比较运算符与“丰富的比较"方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆