摘要:因此我們可以得出結論,如果兩個對象相等的話,那它們的值必然也是相等的。如果定義了一個可比較的對象,那么最好保證對象值相關的屬性在生命周期內不能發生改變,不然會發生意想不到的錯誤。
概述
??大部分的python程序員平時編程的時候,很少關心兩個對象為什么相等,因為教程和經驗來說,他們就應該相等,比如1==1就應該返回True,可是當我們想要定義自己的對象或者修改默認的對象行為時,通常會因為不了解原理而導致各種奇奇怪怪的錯誤。
兩個對象如何相等??兩個對象如何才能相等要比我們想象的復雜很多,但核心的方法是重寫__eq__方法,這個方法返回True,則表示兩個對象相等,否則,就不相等。相反的,如果兩個對象不相等,則重寫__ne__方法。
??默認情況下,如果你沒有實現這個方法,則使用父類(object)的方法。父類的方法比較是的兩個對象的ID(可以通過id方法獲取對象ID),也就是說,如果對象的ID相等,則兩個對象也就相等。因此,我們可以得知,默認情況下,對象只和自己相等。例如:
>>> class A(object): ... pass ... >>> >>> a = A() >>> b = A() >>> a == a True >>> a == b False >>> id(a) 4343310992 >>> id(b) 4343310928
??Python2程序員經常犯的一個錯誤是,只重寫了__eq__方法,而沒有重寫__ne__方法,導致不可預計的錯誤。而Python3會自動重寫__ne__方法,如果你沒有重寫的話。
對象的Hash方法??Python里可Hash的對象,都有一個數字ID代表了它在python里的值,這個ID是由對象的__hash__方法返回的。因此,如果想讓一個對象可Hash,那必須實現__hash__方法和之前提到的__eq__方法。和對象相等一樣,默認情況下,對象的__hash__方法繼承自Object對象,而Object對象的__hash__方法只計算對象ID,因此兩個對象始終擁有兩個不一樣的hash id,不管他們是多么相似。
??當我們把一個不可Hash的對象加入到set或者dict時,會發生什么了?
>>> set().add({}) Traceback (most recent call last): File "", line 1, in TypeError: unhashable type: "dict" unhashable type: "dict"
原因是set()和dict()使用對象的hash值作為內部索引,以便能快速索引到指定對象。因此,同一個對象返回相同的hash id就很重要了。
對象的Hash值在它的生命周期內不能改變??如果你想定義一個比較完美的對象,并且實現了__eq__和__hash__方法來定義對象的比較行為和hash值,那么你就需要保證對象的相關屬性不能發生更改。不然會導致很詭異的錯誤,比如下面的例子。
>>> class C: ... def __init__(self, x): ... self.x = x ... def __repr__(self): ... return "C({"+str(self.x)+"})" ... def __hash__(self): ... return hash(self.x) ... def __eq__(self, other): ... return ( ... self.__class__ == other.__class__ and ... self.x == other.x ... ) >>> d = dict() >>> s = set() >>> c = C(1) >>> d[c] = 42 >>> s.add(c) >>> d, s ({C(1): 42}, {C(1)}) >>> c in s and c in d # c is in both! True >>> c.x = 2 >>> c in s or c in d # c is in neither!? False >>> d, s ({C(2): 42}, {C(2)}) # but...it"s right there!
在我們沒有修改對象的屬性時(c.x=2)之前,所有行為都符合預期。當我們通過c.x=2時修改屬性后,執行c in s or c in d返回False,但是內容卻是修改后的,是不是很奇怪。這也就解釋了為什么str、tuple是可Hash的,而list和dict是不可hash的。
因此我們可以得出結論,如果兩個對象相等的話,那它們的hash值必然也是相等的。
總結講了這么多有什么用了。
當我們遇到unhashable type這個異常時,我們能夠知道為什么報這個錯誤。
如果定義了一個可比較的對象,那么最好保證對象hash值相關的屬性在生命周期內不能發生改變,不然會發生意想不到的錯誤。
轉載自我的博客捕蛇者說文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/41048.html
摘要:第二章與的無縫集成基本特殊方法筆記中有有一些特殊的方法它們允許我們的類和更好的集成和方法通常方法表示的對象對用戶更加友好這個方法是有對象的方法實現的什么時候重寫跟非集合對象一個不包括其他集合對象的簡單對象這類對象格式通常不會特別復 第二章 與Python的無縫集成----基本特殊方法.(Mastering Objecting-oriented Python 筆記) python中有有一...
摘要:有三個用例通過和方法定義相等性檢測和值不可變對象對于有些無狀態對象,例如這些不能被更新的類型。請注意,我們將為不可變對象定義以上兩個。 注:原書作者 Steven F. Lott,原書名為 Mastering Object-oriented Python __hash__() 方法 內置hash()函數會調用給定對象的__hash__()方法。這里hash就是將(可能是復雜的)值縮減...
內置序列 容器序列 list, tuple, collections.deque等這些序列能存放不同類型的數據 扁平序列 str, byte, bytearray, memoryview, array.array, 這些序列只能容納一種類型數據 以上,容器序列存放的是他們所含任意類型對象的引用,而扁平序列存放的是值而不是引用 列表(list)是最基礎也是最重要的序列類型 列表推導 >>> symb...
摘要:中對象包含的三個基本要素,分別是身份標識數據類型值對象之間比較是否相等可以用,也可以用。和都是對對象進行比較判斷作用的,但對對象比較判斷的內容并不相同。是標準操作符中的比較操作符,用來比較判斷兩個對象的值是否相等。 showImg(https://segmentfault.com/img/remote/1460000018591895?w=601&h=203); 在Python中一切都...
閱讀 2109·2023-04-25 17:23
閱讀 2922·2021-11-17 09:33
閱讀 2517·2021-08-21 14:09
閱讀 3595·2019-08-30 15:56
閱讀 2608·2019-08-30 15:54
閱讀 1628·2019-08-30 15:53
閱讀 2132·2019-08-29 13:53
閱讀 1147·2019-08-29 12:31