3

隨着abstract base classes,Python提供了一種方法來知道對象的行爲,而不用實際嘗試它。在標準庫中,我們爲collections.abc中的容器定義了一些ABCs。例如,一個可以測試的說法是迭代:在Python中,如何知道對象是否可以比較?

from collections.abc import Iterable 
def function(argument): 
    if not isinstance(argument, Iterable): 
     raise TypeError('argument must be iterable.') 
    # do stuff with the argument 

我希望會有一個這樣的ABC決定是否一個類的實例可以比擬的,但沒能找到。測試__lt__方法的存在是不夠的。例如,字典無法比較,但__lt__仍然定義(實際上與object相同)。

>>> d1, d2 = {}, {} 
>>> d1 < d2 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
TypeError: unorderable types: dict() < dict() 
>>> hasattr(d1, '__lt__') 
True 

所以我的問題是:是否有一個簡單的方法來做到這一點,而不做比較自己和捕捉TypeError?我的用例與已排序的容器類似:我想在插入第一個元素而不是等待第二個元素時引發異常。我想到了用元素本身相比,但有一個更好的方法:

def insert(self, element): 
    try: 
     element < element 
    except TypeError as e: 
     raise TypeError('element must be comparable.') 
    # do stuff 

回答

4

沒有,有沒有這樣的ABC,因爲ABC 只決定什麼屬性都沒有。 ABCs無法測試實現的性質(或者即使這些屬性實際上是方法)。

的比較方法(__lt____gt____le____ge____eq__)不決定了類將是與一切相媲美的存在。 通常您只能比較相同類型或類別類型的對象;以數字爲例的數字。

因此,類型*與其他不兼容的類型進行比較時,實施比較方法,但返回NotImplemented定點對象。將NotImplemented信號返回給Python,以便在這個問題上給出右邊的值。如果a.__lt__(b)返回NotImplemented那麼b.__gt__(a)也被測試。

基礎object提供的默認實現方法,返回NotImplemented

>>> class Foo: 
...  pass 
... 
>>> Foo() < Foo() 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
TypeError: unorderable types: Foo() < Foo() 
>>> Foo().__lt__ 
<method-wrapper '__lt__' of Foo object at 0x10f1cf860> 
>>> Foo().__lt__(Foo()) 
NotImplemented 

這正是dict.__lt__做:

>>> {}.__lt__({}) 
NotImplemented 

數字,但是,只返回NotImplemented時,另一種是不具有可比性:

>>> (1).__lt__(2) 
True 
>>> (1).__lt__('2') 
NotImplemented 
>>> 1 < 2 
True 
>>> 1 < '2' 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
TypeError: unorderable types: int() < str() 

因此,您的最好的的選擇是簡單地趕上TypeError當值不可比較時拋出。


*我不知道在Python 3標準庫中的任何類型的不執行此時的比較方法。

+0

ABCs不僅說明了那裏的屬性。這就是他們可以執行的所有事情,但是由於他們是選擇性的(需要繼承或明確註冊),大多數ABC可以並且確實定義合同。當'isinstance(x,abc.Sized)'時,假設'x .__ len__'是一個返回非負整數的方法是比較合理的。當然,它不是通過編程來檢查的,但是Python的動態性和真實性一樣,什麼都不能檢查。 – delnan 2015-04-05 12:30:57

+0

@delnan:當然,這是ABC的意圖。但由於比較方法的合同在傳遞不兼容的對象類型時返回'NotImplemented',因此您無法使用ABC測試該合同在該範圍內的執行情況。 – 2015-04-05 12:33:47

+0

@匿名者:請不要添加該功能;調用所有比較方法會導致副作用,因爲自定義類可能會在調用其特殊方法時執行任何操作,包括更改其自己的狀態。 – 2015-04-05 12:36:16