<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
當存取範例物件的某個不存在的屬性時,毫無疑問會報錯,會丟擲 AttributeError。
class A: pass a = A() a.xxx """ AttributeError: 'A' object has no attribute 'xxx' """
但如果我們希望在找不到某個屬性時,不要報錯,而是返回預設值,該怎麼做呢?這個時候我們就需要定義 __getattr__ 方法了,當範例物件找不到某個屬性時會執行此方法。
class Girl: def __init__(self): self.name = "古明地覺" self.age = 17 def get_info(self): return f"name: {self.name}, age: {self.age}" def __getattr__(self, item): return f"你存取了 {item} 屬性" girl = Girl() print(girl.name, girl.age) # 古明地覺 17 print(girl.get_info) # <bound method Girl.get_info...> print(girl.get_info()) # name: 古明地覺, age: 17 print(girl.xxx) # 你存取了 xxx 屬性 print(girl.yyy) # 你存取了 yyy 屬性 print(girl.zzz) # 你存取了 zzz 屬性
所以非常簡單,就是當範例物件存取了一個不存在的屬性時,會執行 __getattr__ 方法。當然,如果屬性存在的話,就不會執行了,而是返回相應的值。
此外 __getattr__ 還有一個用法,就是在模組匯入的時候。假設我們有一個 tools.py,裡面程式碼如下:
def __getattr__(name): return f"{__name__} 中不存在 {name}" name = "古明地覺" age = 17
相信你明白它是幹什麼的了,我們來匯入它:
from tools import name, age, xxx, yyy print(name, age) # 古明地覺 17 print(xxx) # tools 中不存在 xxx print(yyy) # tools 中不存在 yyy import tools print(tools.zzz) # tools 中不存在 zzz
在獲取 tools.py 裡面的屬性時,如果不存在,那麼同樣會去執行 __getattr__,應該還是很簡單的。
__getattribute__ 被稱為屬性攔截器,它比 __getattr__ 要霸道的多,這兩者的區別如下:
我們舉個例子:
class Girl: def __init__(self): self.name = "古明地覺" self.age = 17 def __getattribute__(self, item): return f"獲取屬性: {item}" girl = Girl() print(girl.name) # 獲取屬性: name print(girl.age) # 獲取屬性: age print(girl.xxx) # 獲取屬性: xxx # 即便你想通過屬性字典獲取也是沒有用的 # 因為不管什麼屬性,都會執行 __getattribute__ print(girl.__dict__) # 獲取屬性: __dict__
並且在使用這個方法的時候,一定要謹慎,因為你一不小心就會陷入無限遞迴。
class Girl: def __init__(self): self.name = "古明地覺" self.age = 17 def __getattribute__(self, item): return getattr(self, item) girl = Girl() print(girl.name) # 顯然上面的程式碼會陷入無限遞迴 # 因為 girl.name 會呼叫 __getattribute__ # 而在裡面又執行了 getattr(self, item),還是在獲取屬性 # 所以又會呼叫 __getattribute__,於是會無限遞迴 # 可能有人說,那我換一種方式 # 我將 getattr(self, item) 改成 self.__dict__[item] 可以嗎 # 答案也是不行的,因為 self.__dict__ 仍是在獲取屬性 # 只要獲取屬性,就會觸發 __getattribute__,依舊會陷入無限遞迴
所以 __getattribute__ 非常霸道,那麼我們如何使用它呢?答案是通過父類別。
class Girl: def __init__(self): self.name = "古明地覺" 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 不存在") """ 古明地覺 17 屬性 xxx 不存在 """
當我們呼叫父類別的 __getattribute__ 時,如果屬性存在,它會直接返回;如果範例沒有該屬性,那麼會檢測我們是否定義了 __getattr__,定義了則執行,沒定義則丟擲 AttributeError。我們將這兩個方法結合起來,看一個例子:
class Girl: def __init__(self): self.name = "古明地覺" 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() # 不管屬性是否存在,一律呼叫 __getattribute__ # 然後在裡面我們又呼叫了父類別的 __getattribute__ # 那麼會檢測屬性是否存在,存在則直接獲取對應的值,然後返回 print(girl.name) """ __getattribute__ name 古明地覺 """ # age 也是相同的邏輯,和 name 一樣,這兩個屬性都是存在的 print(girl.age) """ __getattribute__ age 17 """ # 依舊執行 __getattribute__,然後呼叫父類別的 __getattribute__ # 由於屬性 xxx 不存在,於是會執行 __getattr__ print(girl.xxx) """ __getattribute__ xxx __getattr__ xxx 獲取屬性 xxx """
那麼問題來了,這個 __getattribute__ 有啥用呢?該方法被稱為屬性攔截器,顯然它可以起到一個控制屬性存取許可權的作用。
class Girl: def __init__(self): self.name = "古明地覺" self.age = 17 def __getattr__(self, item): return f"屬性 {item} 不存在" def __getattribute__(self, item): if item == "age": return "女人芳齡不可洩露,別問,問就是還不到 18 歲" return super().__getattribute__(item) girl = Girl() # name 屬性存在,所以在 __getattribute__ 中直接返回 print(girl.name) """ 古明地覺 """ # age 也是如此,也是在 __getattribute__ 中直接返回 # 只不過它相當於被攔截了 print(girl.age) """ 女人芳齡不可洩露,別問,問就是還不到 18 歲 """ # 父類別在執行 __getattribute__ 的時候,發現 xxx 屬性不存在 # 於是會觸發 __getattr__ 的執行(如果沒定義則丟擲 AttributeError) print(girl.xxx) """ 屬性 xxx 不存在 """
所以 __getattribute__ 就相當於一個屬性攔截器,不管獲取啥屬性,都要先經過它。如果你發現有一些屬性不想讓外界存取,那麼直接攔截掉即可,比如上面程式碼中的 age 屬性。
然後對於那些可以讓外界存取的屬性,則需要呼叫父類別的 __getattribute__ 幫我們去獲取(因為我們手動獲取的話會陷入無線遞迴),並且在獲取不存在的屬性時也會自動執行 __getattr__。
當然啦,除了屬性,方法也是一樣的。
class Girl: def __init__(self): self.name = "古明地覺" 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) """ 此方法禁止獲取 """ # 預設情況下 girl.get_info 拿到的是一個方法 # 然後再加上小括號就會執行該方法 # 但在 __getattribute__ 中我們將其攔截了,並返回一個字串 # 所以此時 girl.get_info() 就會報錯,因為字串無法被呼叫
以上內容就是 __getattr__ 和 __getattribute__ 的區別與用法,在工作中看看能不能讓它們派上用場。不過說實話,__getattr__ 用的還是蠻頻繁的,而 __getattribute__ 則用的不多,至少我就很少用。
到此這篇關於一文解密Python中_getattr_和_getattribute_的用法與區別的文章就介紹到這了,更多相關Python getattr getattribute內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45