一文解密Python中_getattr_和_getattribute_的用法與區(qū)別
__getattr__
當(dāng)訪問(wèn)實(shí)例對(duì)象的某個(gè)不存在的屬性時(shí),毫無(wú)疑問(wèn)會(huì)報(bào)錯(cuò),會(huì)拋出 AttributeError。
class?A: ????pass a?=?A() a.xxx """ AttributeError:?'A'?object?has?no?attribute?'xxx' """
但如果我們希望在找不到某個(gè)屬性時(shí),不要報(bào)錯(cuò),而是返回默認(rèn)值,該怎么做呢?這個(gè)時(shí)候我們就需要定義 __getattr__ 方法了,當(dāng)實(shí)例對(duì)象找不到某個(gè)屬性時(shí)會(huì)執(zhí)行此方法。
class?Girl: ????def?__init__(self): ????????self.name?=?"古明地覺(jué)" ????????self.age?=?17 ????def?get_info(self): ????????return?f"name:?{self.name},?age:?{self.age}" ????def?__getattr__(self,?item): ????????return?f"你訪問(wèn)了?{item}?屬性" girl?=?Girl() print(girl.name,?girl.age)??#?古明地覺(jué)?17 print(girl.get_info)??#?<bound?method?Girl.get_info...> print(girl.get_info())??#?name:?古明地覺(jué),?age:?17 print(girl.xxx)??#?你訪問(wèn)了?xxx?屬性 print(girl.yyy)??#?你訪問(wèn)了?yyy?屬性 print(girl.zzz)??#?你訪問(wèn)了?zzz?屬性
所以非常簡(jiǎn)單,就是當(dāng)實(shí)例對(duì)象訪問(wèn)了一個(gè)不存在的屬性時(shí),會(huì)執(zhí)行 __getattr__ 方法。當(dāng)然,如果屬性存在的話,就不會(huì)執(zhí)行了,而是返回相應(yīng)的值。
此外 __getattr__ 還有一個(gè)用法,就是在模塊導(dǎo)入的時(shí)候。假設(shè)我們有一個(gè) tools.py,里面代碼如下:
def?__getattr__(name): ????return?f"{__name__}?中不存在?{name}" name?=?"古明地覺(jué)" age?=?17
相信你明白它是干什么的了,我們來(lái)導(dǎo)入它:
from?tools?import?name,?age,?xxx,?yyy print(name,?age)??#?古明地覺(jué)?17 print(xxx)??#?tools?中不存在?xxx print(yyy)??#?tools?中不存在?yyy import?tools print(tools.zzz)??#?tools?中不存在?zzz
在獲取 tools.py 里面的屬性時(shí),如果不存在,那么同樣會(huì)去執(zhí)行 __getattr__,應(yīng)該還是很簡(jiǎn)單的。
__getattribute__
__getattribute__ 被稱(chēng)為屬性攔截器,它比 __getattr__ 要霸道的多,這兩者的區(qū)別如下:
- __getattr__:當(dāng)訪問(wèn)的屬性不存在時(shí),才會(huì)執(zhí)行此方法;
- __getattribute__:不管訪問(wèn)的屬性是否存在,一律執(zhí)行此方法;
我們舉個(gè)例子:
class?Girl: ????def?__init__(self): ????????self.name?=?"古明地覺(jué)" ????????self.age?=?17 ????def?__getattribute__(self,?item): ????????return?f"獲取屬性:?{item}" girl?=?Girl() print(girl.name)??#?獲取屬性:?name print(girl.age)??#?獲取屬性:?age print(girl.xxx)??#?獲取屬性:?xxx #?即便你想通過(guò)屬性字典獲取也是沒(méi)有用的 #?因?yàn)椴还苁裁磳傩?,都?huì)執(zhí)行?__getattribute__ print(girl.__dict__)??#?獲取屬性:?__dict__
并且在使用這個(gè)方法的時(shí)候,一定要謹(jǐn)慎,因?yàn)槟阋徊恍⌒木蜁?huì)陷入無(wú)限遞歸。
class?Girl: ????def?__init__(self): ????????self.name?=?"古明地覺(jué)" ????????self.age?=?17 ????def?__getattribute__(self,?item): ????????return?getattr(self,?item) girl?=?Girl() print(girl.name) #?顯然上面的代碼會(huì)陷入無(wú)限遞歸 #?因?yàn)?girl.name?會(huì)調(diào)用?__getattribute__ #?而在里面又執(zhí)行了?getattr(self,?item),還是在獲取屬性 #?所以又會(huì)調(diào)用?__getattribute__,于是會(huì)無(wú)限遞歸 #?可能有人說(shuō),那我換一種方式 #?我將?getattr(self,?item)?改成?self.__dict__[item]?可以嗎 #?答案也是不行的,因?yàn)?self.__dict__?仍是在獲取屬性 #?只要獲取屬性,就會(huì)觸發(fā)?__getattribute__,依舊會(huì)陷入無(wú)限遞歸
所以 __getattribute__ 非常霸道,那么我們?nèi)绾问褂盟兀看鸢甘峭ㄟ^(guò)父類(lèi)。
class?Girl: ????def?__init__(self): ????????self.name?=?"古明地覺(jué)" ????????self.age?=?17 ????def?__getattribute__(self,?item): ????????return?super().__getattribute__(item) girl?=?Girl() print(girl.name) print(girl.age) try: ????girl.xxx except?AttributeError: ????print("屬性?xxx?不存在") """ 古明地覺(jué) 17 屬性?xxx?不存在 """
當(dāng)我們調(diào)用父類(lèi)的 __getattribute__ 時(shí),如果屬性存在,它會(huì)直接返回;如果實(shí)例沒(méi)有該屬性,那么會(huì)檢測(cè)我們是否定義了 __getattr__,定義了則執(zhí)行,沒(méi)定義則拋出 AttributeError。我們將這兩個(gè)方法結(jié)合起來(lái),看一個(gè)例子:
class?Girl: ????def?__init__(self): ????????self.name?=?"古明地覺(jué)" ????????self.age?=?17 ????def?__getattr__(self,?item): ????????print(f"__getattr__?{item}") ????????return?f"獲取屬性?{item}" ????def?__getattribute__(self,?item): ????????print(f"__getattribute__?{item}") ????????return?super().__getattribute__(item) girl?=?Girl() #?不管屬性是否存在,一律調(diào)用?__getattribute__ #?然后在里面我們又調(diào)用了父類(lèi)的?__getattribute__ #?那么會(huì)檢測(cè)屬性是否存在,存在則直接獲取對(duì)應(yīng)的值,然后返回 print(girl.name) """ __getattribute__?name 古明地覺(jué) """ #?age?也是相同的邏輯,和?name?一樣,這兩個(gè)屬性都是存在的 print(girl.age) """ __getattribute__?age 17 """ #?依舊執(zhí)行?__getattribute__,然后調(diào)用父類(lèi)的?__getattribute__ #?由于屬性?xxx?不存在,于是會(huì)執(zhí)行?__getattr__ print(girl.xxx) """ __getattribute__?xxx __getattr__?xxx 獲取屬性?xxx """
那么問(wèn)題來(lái)了,這個(gè) __getattribute__ 有啥用呢?該方法被稱(chēng)為屬性攔截器,顯然它可以起到一個(gè)控制屬性訪問(wèn)權(quán)限的作用。
class?Girl: ????def?__init__(self): ????????self.name?=?"古明地覺(jué)" ????????self.age?=?17 ????def?__getattr__(self,?item): ????????return?f"屬性?{item}?不存在" ????def?__getattribute__(self,?item): ????????if?item?==?"age": ????????????return?"女人芳齡不可泄露,別問(wèn),問(wèn)就是還不到?18?歲" ????????return?super().__getattribute__(item) girl?=?Girl() #?name?屬性存在,所以在?__getattribute__?中直接返回 print(girl.name) """ 古明地覺(jué) """ #?age?也是如此,也是在?__getattribute__?中直接返回 #?只不過(guò)它相當(dāng)于被攔截了 print(girl.age) """ 女人芳齡不可泄露,別問(wèn),問(wèn)就是還不到?18?歲 """ #?父類(lèi)在執(zhí)行?__getattribute__?的時(shí)候,發(fā)現(xiàn)?xxx?屬性不存在 #?于是會(huì)觸發(fā)?__getattr__?的執(zhí)行(如果沒(méi)定義則拋出?AttributeError) print(girl.xxx) """ 屬性?xxx?不存在 """
所以 __getattribute__ 就相當(dāng)于一個(gè)屬性攔截器,不管獲取啥屬性,都要先經(jīng)過(guò)它。如果你發(fā)現(xiàn)有一些屬性不想讓外界訪問(wèn),那么直接攔截掉即可,比如上面代碼中的 age 屬性。
然后對(duì)于那些可以讓外界訪問(wèn)的屬性,則需要調(diào)用父類(lèi)的 __getattribute__ 幫我們?nèi)カ@?。ㄒ?yàn)槲覀兪謩?dòng)獲取的話會(huì)陷入無(wú)線遞歸),并且在獲取不存在的屬性時(shí)也會(huì)自動(dòng)執(zhí)行 __getattr__。
當(dāng)然啦,除了屬性,方法也是一樣的。
class?Girl: ????def?__init__(self): ????????self.name?=?"古明地覺(jué)" ????????self.age?=?17 ????def?get_info(self): ????????return?f"name:?{self.name},?age:?{self.age}" ????def?__getattribute__(self,?item): ????????if?item?==?"get_info": ????????????return?"此方法禁止獲取" ????????return?super().__getattribute__(item) girl?=?Girl() print(girl.get_info) """ 此方法禁止獲取 """ #?默認(rèn)情況下?girl.get_info?拿到的是一個(gè)方法 #?然后再加上小括號(hào)就會(huì)執(zhí)行該方法 #?但在?__getattribute__?中我們將其攔截了,并返回一個(gè)字符串 #?所以此時(shí)?girl.get_info()?就會(huì)報(bào)錯(cuò),因?yàn)樽址疅o(wú)法被調(diào)用
以上內(nèi)容就是 __getattr__ 和 __getattribute__ 的區(qū)別與用法,在工作中看看能不能讓它們派上用場(chǎng)。不過(guò)說(shuō)實(shí)話,__getattr__ 用的還是蠻頻繁的,而 __getattribute__ 則用的不多,至少我就很少用。
到此這篇關(guān)于一文解密Python中_getattr_和_getattribute_的用法與區(qū)別的文章就介紹到這了,更多相關(guān)Python getattr getattribute內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
解決在keras中使用model.save()函數(shù)保存模型失敗的問(wèn)題
這篇文章主要介紹了解決在keras中使用model.save()函數(shù)保存模型失敗的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-05-05Python機(jī)器學(xué)習(xí)NLP自然語(yǔ)言處理基本操作新聞分類(lèi)
本文是Python機(jī)器學(xué)習(xí)NLP自然語(yǔ)言處理系列文章,開(kāi)始我們自然語(yǔ)言處理 (NLP) 的學(xué)習(xí)旅程. 本文主要學(xué)習(xí)NLP自然語(yǔ)言處理基本操作新聞分類(lèi)2021-09-09Pytorch 實(shí)現(xiàn)權(quán)重初始化
今天小編就為大家分享一篇Pytorch 實(shí)現(xiàn)權(quán)重初始化,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-12-12Python實(shí)現(xiàn)文件按照日期命名的方法
這篇文章主要介紹了Python實(shí)現(xiàn)文件按照日期命名的方法,涉及Python針對(duì)文件的遍歷、讀寫(xiě)及時(shí)間操作相關(guān)技巧,需要的朋友可以參考下2015-07-07基于Pytorch的神經(jīng)網(wǎng)絡(luò)之Regression的實(shí)現(xiàn)
本文主要介紹了基于Pytorch的神經(jīng)網(wǎng)絡(luò)之Regression的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-03-03python 利用panda 實(shí)現(xiàn)列聯(lián)表(交叉表)
這篇文章主要介紹了python 利用panda 實(shí)現(xiàn)列聯(lián)表(交叉表),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2021-02-02python中使用numpy包的向量矩陣相乘np.dot和np.matmul實(shí)現(xiàn)
本文主要介紹了python中使用numpy包的向量矩陣相乘np.dot和np.matmul實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-02-02