亂寫__eq__會(huì)發(fā)生啥?請看代碼..
>>> class A:... def __eq__(self, other): # 不論發(fā)生什么,只要有==做比較,就返回True... return True... >>> a = A()>>> b = A()>>> a == bTrue>>> a != b # 這個(gè)地方為什么會(huì)返回False?False>>> a > bTraceback (most recent call last): File "<ipython-input-7-1e61210fe837>", line 1, in <module> a > bTypeError: unorderable types: A() > A()>>> x = [1,2,3,b,4,5]>>> x.index(b) # 咦?0>>> x.index(2)1>>> x.index(4) # 誒?3>>> x.index(5) # 艾瑪,啥情況?3>>> x.index(6) # 媽呀!3>>> x.index(a) # 233330 當(dāng)時(shí)初次看到這個(gè)就被這神奇的現(xiàn)象吸引了,發(fā)現(xiàn)新大陸了的感覺。以為發(fā)現(xiàn)了BUG。。。問我隔壁的小哥,也說不明白。但可以確定的是,如果我沒有重寫這個(gè)__eq__函數(shù)的話,下面的操作都是正常的,找不到的就找不到,能找到的就返回正確的index。所以肯定是我__eq__函數(shù)寫差了,源碼看不到也不好搜索,于是跑去看文檔。文檔這里寫道:
- object.__lt__(self, other)
- object.__le__(self, other)
- object.__eq__(self, other)
- object.__ne__(self, other)
- object.__gt__(self, other)
- object.__ge__(self, other)
These are the so-called “rich comparison” methods. 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).
A rich comparison method may return the singleton NotImplemented if it does not implement the operation for a given pair of arguments. By convention, False and True are returned for a successful comparison. However, these methods can return any value, so if the comparison operator is used in a Boolean context (e.g., in the condition of an if statement), Python will call bool() on the value to determine if the result is true or false.
There are no implied relationships among the comparison operators. The truth of x==y does not imply that x!=y is false. Accordingly, when defining __eq__(), one should also define __ne__() so that the operators will behave as expected. See the paragraph on __hash__() for some important notes on creating hashable objects which support custom comparison operations and are usable as dictionary keys.
There are no swapped-argument versions of these methods (to be used when the left argument does not support the operation but the right argument does); rather, __lt__() and __gt__() are each other’s reflection, __le__() and __ge__() are each other’s reflection, and __eq__() and __ne__() are their own reflection.
Arguments to rich comparison methods are never coerced.
To automatically generate ordering operations from a single root operation, see functools.total_ordering().
1.這些比較函數(shù)都稱為rich comparison,正常情況下,它們回返回真或假。實(shí)際上這些函數(shù)都可以返回任意類型的值,如果這些比較被運(yùn)用在布爾環(huán)境中的時(shí)候,比方說if 語句的條件中時(shí),python 會(huì)調(diào)用bool()函數(shù)來確認(rèn)當(dāng)前的返回值是真還是假。(劃橫線的地方不會(huì)翻譯=。=)
2.這些函數(shù)的定義之間并沒有引申的含義,比如說如果a==b是真,并不代表a!=b一定是假。所以我們在定義__eq__函數(shù)的時(shí)候也應(yīng)該同時(shí)定義__ne__函數(shù)以確保我們能夠得到我們想要的結(jié)果。如果我們想了解可哈希對(duì)象的比較的信息,我們最好去看看__hash__()的文檔。這里就不展開了,具體文章在這里(實(shí)習(xí)小記-python中可哈希對(duì)象是個(gè)啥?what is hashable object in python?)
3.這些函數(shù)并沒有可替換參數(shù)之說(像是左邊的參數(shù)不支持這個(gè)函數(shù),而右邊的參數(shù)支持。)這里要說的是,__lt__()函數(shù)和__gt__()函數(shù)他們兩個(gè)的取值是一定相反的;__le__()和__ge__()也一定是取相反的;但是__eq__()函數(shù)和__ne__()函數(shù)是各自獨(dú)立定義的。相互之間并沒有關(guān)系。這也就是2里面提到的。
4.比較這類操作的參數(shù)是不會(huì)類型轉(zhuǎn)換的。(如果a,b做比較,a是浮點(diǎn),b是整數(shù),比較結(jié)束后b不會(huì)變成浮點(diǎn)類型?)
5.如果我們希望能夠在一些情況下自動(dòng)排序,那么請參考functools.total_ordering()
讀到這里我們在回到之前的代碼中看看,到底發(fā)生了什么
>>> class A:... def __eq__(self, other): # 不論發(fā)生什么,只要有==做比較,就返回True... return True... >>> a = A()>>> b = A()>>> a == bTrue>>> a != b # 這個(gè)地方為什么會(huì)返回False?False>>> a > bTraceback (most recent call last): File "<ipython-input-7-1e61210fe837>", line 1, in <module> a > bTypeError: unorderable types: A() > A()>>> x = [1,2,3,b,4,5]>>> x.index(b) # 首先拿x中的1與b做比較,應(yīng)該是==的比較,由于b.__eq__()無論什么情況下都返回True。所以python以為第一個(gè)元素就是b,于是返回index 00>>> x.index(2)1>>> x.index(4) # 這里拿4做比較,x中的元素安順序比較,1,2,3為False,但當(dāng)比較到b時(shí)由于b的坑爹屬性返回True,以為找到了,返回index 33>>> x.index(5) # 同上3>>> x.index(6) # 同上3>>> x.index(a) # 和第一次相比的原因是一樣的。0
那么問題來了,如果我們需要一種類,該類的實(shí)例做比較的時(shí)候比較類中屬性,屬性相等返回True,在列表中查找時(shí)也能正確查找,應(yīng)該如何寫呢?請看下面代碼:
>>> class A:... def __init__(self, x):... self.x = x... def __eq__(self, other):... try:... return self.x == other.x... except AttributeError:... return False... def __ne__(self, other):... try:... return self.x != other.x... except AttributeError: # 發(fā)現(xiàn)兩者不可比,返回類型錯(cuò)誤... raise TypeError('this two argument is not comparable!')... >>> a = A(1)>>> b = A(1)>>> c = A(2)>>> a == bTrue>>> a != bFalse>>> a == cFalse>>> a != c # 相同類型做比較,確實(shí)不相同True>>> a == 1 # 不同類型做比較,返回FalseFalse>>> a != 1 # 判斷不同類型是否不等,報(bào)類型錯(cuò)誤Traceback (most recent call last): File "<ipython-input-52-30ec16ffc1a6>", line 1, in <module> a != 1 File "<ipython-input-43-70049527ba59>", line 13, in __ne__ raise TypeError('this two argument is not comparable!')TypeError: this two argument is not comparable!>>> list = [1,2,3,b,4,5]>>> list.index(3)2>>> list.index(b) # 成功找到!3>>> list.index(a) # 實(shí)例不同,但是self.x相等,屬于同一個(gè)。3>>> a in listTrue>>> b in listTrue
新聞熱點(diǎn)
疑難解答
圖片精選
網(wǎng)友關(guān)注