欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Python中使用__hash__和__eq__方法的問題

 更新時(shí)間:2022年09月27日 16:44:26   作者:Inotime  
這篇文章主要介紹了Python中使用__hash__和__eq__方法的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

Python使用__hash__和__eq__的問題

  • 代碼版本3.6.3    
  • 文檔版本:3.6.6

 object.__hash__(self)

Called by built-in function hash() and for operations on members of hashed collections including set, frozenset, and dict.

 __hash__()方法會(huì)被上述四種情況調(diào)用。

If a class does not define an __eq__() method it should not define a __hash__()operation either; if it defines __eq__() but not __hash__(), its instances will not be usable as items in hashable collections. If a class defines mutable objects and implements an __eq__() method, it should not implement __hash__(), since the implementation of hashable collections requires that a key’s hash value is immutable (if the object’s hash value changes, it will be in the wrong hash bucket).

如果自定義類沒定義__eq__()方法,那也不應(yīng)該定義__hash__()方法。 

如果定義了__eq__()方法沒有定義__hash__()方法,那么它無法作為哈希集合的元素使用(這個(gè)hashable collections值得是set、frozenset和dict)。

這其實(shí)是因?yàn)橹貙慱_eq__()方法后會(huì)默認(rèn)把__hash__賦為None(文檔后面有說),像list一樣。 

class A:
? ? def __eq__(self, other):
? ? ? ? pass
?
?
a = A()
?
print(a.__hash__) ?# None
hash(a)
?
?
# TypeError: unhashable type: 'A'

還專門說明:如果定義可變對(duì)象的類實(shí)現(xiàn)了__eq__()方法,就不要再實(shí)現(xiàn)__hash__()方法,否則這個(gè)對(duì)象的hash值發(fā)生變化會(huì)導(dǎo)致被放在錯(cuò)誤的哈希桶中。這個(gè)可以用字典試一下,你的鍵值不在是一一對(duì)應(yīng)的,只要能讓這兩個(gè)方法返回一致的對(duì)象都能改動(dòng)那個(gè)本不屬于自己的值,這篇文章的第五個(gè)例子就是這種情況。

User-defined classes have __eq__() and __hash__() methods by default; with them, all objects compare unequal (except with themselves) and x.__hash__() returns an appropriate value such that x == y implies both that x is y and hash(x) == hash(y). 

用戶定義的類默認(rèn)都有__eq__()和__hash__()方法,這是從object繼承的,如果你不重寫任何一個(gè),那么對(duì)這個(gè)類的兩個(gè)實(shí)例x,y來說,x is y ,x == y , hash(x) == hash(y)會(huì)同時(shí)成立/不成立,即只有在x就是y的時(shí)候成立。

A class that overrides __eq__() and does not define __hash__() will have its __hash__()implicitly set to None. When the __hash__() method of a class is None, instances of the class will raise an appropriate TypeError when a program attempts to retrieve their hash value, and will also be correctly identified as unhashable when checking isinstance(obj, collections.abc.Hashable).

 重寫了__eq__()方法的類會(huì)隱式的把__hash__賦為None。當(dāng)獲取實(shí)例的哈希值即用到了__hash__()方法時(shí)(只有上文提到的四種情況會(huì)用到這個(gè)方法)就會(huì)拋出TypeError錯(cuò)誤,上文例子演示過了。

并且isinstance判斷類型也能正確判斷。

# 直接安裝不成功 ?pip install collections2 才行
# collections2==0.3.0 ?A set of improved data types inspired by the standard library's collections module.
import collections
?
?
class A:
? ? def __eq__(self, other):
? ? ? ? pass
?
?
class B:
? ? pass
?
?
a = A()
b = B()
?
print(isinstance(a, collections.abc.Hashable)) ?# False
print(isinstance(b, collections.abc.Hashable)) ?# True

If a class that overrides __eq__() needs to retain the implementation of __hash__() from a parent class, the interpreter must be told this explicitly by setting __hash__ =<ParentClass>.__hash__.

If a class that does not override __eq__() wishes to suppress hash support, it should include __hash__ = None in the class definition. A class which defines its own __hash__() that explicitly raises a TypeError would be incorrectly identified as hashable by an isinstance(obj, collections.abc.Hashable) call.

 如果一個(gè)類重寫了__eq__()方法還需要能使用父類的__hash__()方法(上文已說默認(rèn)情況下是被賦值為None了),那就需要明確的說明一下:例class A;如果一個(gè)類沒有重寫__eq__()方法而又需要讓__hash__()失效,那就要明確的賦值為None,像list、set等的源碼那樣。

如果你重寫了一個(gè)會(huì)拋出異常的__hash__()方法,雖然使用時(shí)會(huì)拋出異常,但是類型判斷還是會(huì)判斷為是可哈希的,這是要注意的:例class B。

import collections
?
?
class A:
? ? def __eq__(self, other):
? ? ? ? pass
? ? __hash__ = object.__hash__
?
?
class B:
? ? def __hash__(self):
? ? ? ? raise TypeError('There is an error!')
?
?
a = A()
b = B()
?
print(isinstance(a, collections.abc.Hashable))
print(isinstance(b, collections.abc.Hashable))
hash(b)
?
?
# 結(jié)果:
# True
# True
# ...line 12, in __hash__...
# TypeError: There is an error!

文檔位置:3.6.6 object.__hash__

Python類中特殊方法__eq__和__hash__關(guān)系

class Point(object):

    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __repr__(self):
        return repr((self.id, self.x, self.y))

    def __eq__(self, other):
        return self.x == other.y and self.y == self.y

    def __hash__(self):
        return hash((self.x, self.y))

上面定義了一個(gè)二維點(diǎn)的類其中__repr__主要用來以一個(gè)字符串表示該類的實(shí)例,例如Point(1,2),在調(diào)試時(shí)打印該點(diǎn)會(huì)獲得字符串(1,2)。

當(dāng)對(duì)兩個(gè)點(diǎn)的實(shí)例進(jìn)行值的比較時(shí),比如p1=Point(1,1) p2=Point(1,2),判斷p1==p2時(shí)__eq__()會(huì)被調(diào)用,用以判斷兩個(gè)實(shí)例是否相等。在上述代碼中定義了只要x和y的坐標(biāo)相同,兩個(gè)點(diǎn)相等。需要注意,__eq__()對(duì)is不生效,==是比較的值,而is比較的是引用,也就是內(nèi)存地址。舉個(gè)例子,p1=Point(1,1) p2=Point(1,1),p1==p2為True,p1 is p2為False,只有p1 is p1為True。

在Python中對(duì)象分為可哈希對(duì)象和不可哈希對(duì)象,可哈希對(duì)象如字符串、數(shù)字、自定義的類、frozenset、元組,被稱作不可變對(duì)象,不可哈希對(duì)象如字典、列表、集合,被稱作可變對(duì)象。這里的不可變不是對(duì)象的值不可變,而是指對(duì)象創(chuàng)建后其hash值在其生命周期內(nèi)不會(huì)改變。用函數(shù)hash()取可哈希對(duì)象的hash值,只要是同一對(duì)象其hash值不會(huì)改變;而對(duì)不可哈希對(duì)象取hash值,例如對(duì)列表取hash值,會(huì)報(bào)錯(cuò),返回TypeError: unhashable type: 'list'??晒?duì)象因其hash值不變可以用作字典的key,而不可哈希對(duì)象則不行。

當(dāng)需要對(duì)類的一個(gè)實(shí)例取其hash值時(shí),會(huì)調(diào)用__hash__()。一般來說,會(huì)把實(shí)例的所有屬性打包成元組,返回其hash值,從而實(shí)現(xiàn)自定義__hash__()。在用set()去重時(shí)就是對(duì)比hash值是否一樣,如果兩個(gè)對(duì)象hash值一樣代表重復(fù)。

用戶定義的類默認(rèn)帶有__eq__()和 __hash__()方法;使用它們與任何對(duì)象(自己除外)比較必定不相等,并且 x.__hash__()會(huì)返回一個(gè)恰當(dāng)?shù)闹狄源_保 x == y 同時(shí)意味著 x is y且 hash(x) == hash(y)。

如果一個(gè)類沒有定義__eq__()方法,那么也不應(yīng)該定義 __hash__()操作;如果它定義了__eq__()但沒有定義 __hash__(),那么__hash__()會(huì)被隱式地設(shè)為None,這個(gè)類就變成了不可哈希對(duì)象。如果一個(gè)類定義了可變對(duì)象并實(shí)現(xiàn)了 __eq__()方法,則不應(yīng)該實(shí)現(xiàn)__hash__(),因?yàn)榭晒<膶?shí)現(xiàn)要求鍵的哈希集是不可變的。例如,Point類中添加一個(gè)屬性li是一個(gè)列表,由于列表不可哈希所以強(qiáng)行放入包含屬性的元組中并返回其哈希值會(huì)報(bào)錯(cuò)。



如果使用默認(rèn)的__hash__()則不論如何改變一個(gè)實(shí)例的值其hash值都不變;反之,使用本文這種自定義的__hash__()方法,實(shí)例的值改變后,hash值就會(huì)改變。因此,自定義__hash__()方法的類的實(shí)例不應(yīng)該作為字典的key(強(qiáng)行作為key不會(huì)報(bào)錯(cuò),但是改變實(shí)例的屬性值會(huì)導(dǎo)致找不到key對(duì)應(yīng)的value),key的哈希值必須唯一不可變,key的hash值改變會(huì)導(dǎo)致找不到key對(duì)應(yīng)的value。






以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • 在Python中使用cookielib和urllib2配合PyQuery抓取網(wǎng)頁信息

    在Python中使用cookielib和urllib2配合PyQuery抓取網(wǎng)頁信息

    這篇文章主要介紹了在Python中使用cookielib和rllib2配合PyQuery抓取網(wǎng)頁信息的教程,主要是利用PyQuery解析HTML來實(shí)現(xiàn),需要的朋友可以參考下
    2015-04-04
  • Python?OpenCV中cv2.minAreaRect實(shí)例解析

    Python?OpenCV中cv2.minAreaRect實(shí)例解析

    minAreaRect的主要作用是獲取一個(gè)多邊形(就是有很多個(gè)點(diǎn)組成的一個(gè)圖形)的最小旋轉(zhuǎn)矩形(旋轉(zhuǎn)矩形就是我們平常見到的水平框帶了角度),這篇文章主要給大家介紹了關(guān)于Python?OpenCV中cv2.minAreaRect的相關(guān)資料,需要的朋友可以參考下
    2022-11-11
  • 詳解超星腳本出現(xiàn)亂碼問題的解決方法(Python)

    詳解超星腳本出現(xiàn)亂碼問題的解決方法(Python)

    超星助手是一款為孩子們提供學(xué)習(xí)的軟件,支持用戶們后臺(tái)運(yùn)行多開等,還可以簽到,查題等多功能,下面這篇文章主要給大家介紹了關(guān)于超星腳本出現(xiàn)亂碼問題的解決方法,需要的朋友可以參考下
    2022-05-05
  • python刪除本地夾里重復(fù)文件的方法

    python刪除本地夾里重復(fù)文件的方法

    這篇文章主要為大家詳細(xì)介紹了python刪除本地夾里重復(fù)文件的方法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-05-05
  • Python 和 JS 有哪些相同之處

    Python 和 JS 有哪些相同之處

    Python 是一門運(yùn)用很廣泛的語言,自動(dòng)化腳本、爬蟲,甚至在深度學(xué)習(xí)領(lǐng)域也都有 Python 的身影。下面通過本文給大家介紹Python 和 JS 有哪些相同之處,需要的朋友參考下吧
    2017-11-11
  • 如何用Python對(duì)數(shù)學(xué)函數(shù)進(jìn)行求值、求偏導(dǎo)

    如何用Python對(duì)數(shù)學(xué)函數(shù)進(jìn)行求值、求偏導(dǎo)

    這篇文章主要介紹了如何用Python對(duì)數(shù)學(xué)函數(shù)進(jìn)行求值、求偏導(dǎo)問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-05-05
  • Jinja2過濾器的使用、控制語句示例詳解

    Jinja2過濾器的使用、控制語句示例詳解

    在Python中,如果需要對(duì)某個(gè)變量進(jìn)行處理,我們可以通過函數(shù)來實(shí)現(xiàn),這篇文章主要介紹了Jinja2過濾器的使用、控制語句,需要的朋友可以參考下
    2023-03-03
  • python操作Excel神器openpyxl看這一篇就夠了

    python操作Excel神器openpyxl看這一篇就夠了

    Python使用openpyxl讀寫excel文件這是一個(gè)第三方庫,可以處理xlsx格式的Excel文件,下面這篇文章主要給大家介紹了關(guān)于python操作Excel神器openpyxl的相關(guān)資料,需要的朋友可以參考下
    2023-04-04
  • Python符號(hào)計(jì)算之實(shí)現(xiàn)函數(shù)極限的方法

    Python符號(hào)計(jì)算之實(shí)現(xiàn)函數(shù)極限的方法

    這篇文章主要介紹了Python符號(hào)計(jì)算之實(shí)現(xiàn)函數(shù)極限的方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-07-07
  • python之np.argmax()及對(duì)axis=0或者1的理解

    python之np.argmax()及對(duì)axis=0或者1的理解

    這篇文章主要介紹了python之np.argmax()及對(duì)axis=0或者1的理解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-06-06

最新評(píng)論