簡體   English   中英

比較運算符與Python中的“豐富比較”方法

[英]Comparison operators vs “rich comparison” methods in Python

有人可以解釋我兩者之間的差異。 那些通常是等價的嗎? 也許我在這里完全錯了,但我認為每個比較運算符都必然與一個“豐富的比較”方法有關。 這來自文檔:

運算符符號和方法名稱之間的對應關系如下:

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中,並非所有對象都支持比較運算符。 令我驚訝的是,兩個版本在調用__lt__()時返回NotImplemented單例。

這依賴於__cmp__ magic方法,這是富比較運算符要替換的方法:

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

至於排序邏輯 ,這里是Python 2.7 文檔

當且僅當它們具有相等(鍵,值)對時,映射(dict的實例)才相等。 鍵和值的相等比較強制實現反身性。

平等以外的結果一致地得到解決,但沒有另外定義。

用腳注:

早期版本的Python使用了排序(鍵,值)列表的詞典比較,但對於比較相等的常見情況,這是非常昂貴的。 甚至早期版本的Python僅通過標識比較字典,但這引起了驚喜,因為人們希望能夠通過將字典與{}進行比較來測試字典的空白。

而且,在Python 3.0中,訂購已經簡化。 這來自文檔

當操作數沒有有意義的自然順序時(<, <=, >=, >)排序比較運算符(<, <=, >=, >)引發TypeError異常。

builtin.sorted()list.sort()不再接受提供比較函數的cmp參數。 請改用key參數。

應將cmp()函數視為已消失,並且不再支持__cmp__()特殊方法。 使用__lt__()進行排序, __eq__() __hash__()使用__hash__() ,並根據需要進行其他豐富的比較。 (如果你真的需要cmp()功能,你可以使用表達式(a > b) - (a <> b)作為cmp(a, b)的等價物。)

所以,明確地說,在Python 2中,由於沒有實現豐富的比較運算符, dict對象將從數據模型文檔中回退到__cmp__

object.__cmp__(self, other)
如果沒有定義豐富的比較(見上文),則通過比較操作調用。 如果self <other則返回負整數,如果self == other則返回0,如果self> other則返回正整數。

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM