摘要:起步的提供一系列和屬性訪問有關的特殊方法。本文闡述它們的區別和用法。屬性的訪問機制一般情況下,屬性訪問的默認行為是從對象的字典中獲取,并當獲取不到時會沿著一定的查找鏈進行查找。則這個類的對象稱為描述符。
起步
python的提供一系列和屬性訪問有關的特殊方法:__get__, __getattr__, __getattribute__, __getitem__ 。本文闡述它們的區別和用法。
屬性的訪問機制一般情況下,屬性訪問的默認行為是從對象的字典中獲取,并當獲取不到時會沿著一定的查找鏈進行查找。例如 a.x 的查找鏈就是,從 a.__dict__["x"] ,然后是 type(a).__dict__["x"] ,再通過 type(a) 的基類開始查找。
若查找鏈都獲取不到屬性,則拋出 AttributeError 異常。
__getattr__ 方法這個方法是當對象的屬性不存在是調用。如果通過正常的機制能找到對象屬性的話,不會調用 __getattr__ 方法。
class A: a = 1 def __getattr__(self, item): print("__getattr__ call") return item t = A() print(t.a) print(t.b) # output 1 __getattr__ call b__getattribute__ 方法
這個方法會被無條件調用。不管屬性存不存在。如果類中還定義了 __getattr__ ,則不會調用 __getattr__() 方法,除非在 __getattribute__ 方法中顯示調用__getattr__() 或者拋出了 AttributeError 。
class A: a = 1 def __getattribute__(self, item): print("__getattribute__ call") raise AttributeError def __getattr__(self, item): print("__getattr__ call") return item t = A() print(t.a) print(t.b)
所以一般情況下,為了保留 __getattr__ 的作用,__getattribute__() 方法中一般返回父類的同名方法:
def __getattribute__(self, item): return object.__getattribute__(self, item)
使用基類的方法來獲取屬性能避免在方法中出現無限遞歸的情況。
__get__ 方法這個方法比較簡單說明,它與前面的關系不大。
如果一個類中定義了 __get__(), __set__() 或 __delete__() 中的任何方法。則這個類的對象稱為描述符。
class Descri(object): def __get__(self, obj, type=None): print("call get") def __set__(self, obj, value): print("call set") class A(object): x = Descri() a = A() a.__dict__["x"] = 1 # 不會調用 __get__ a.x # 調用 __get__
如果查找的屬性是在描述符對象中,則這個描述符會覆蓋上文說的屬性訪問機制,體現在查找鏈的不同,而這個行文也會因為調用的不同而稍有不一樣:
如果調用是對象實例(題目中的調用方式),a.x 則轉換為調用: 。type(a).__dict__["x"].__get__(a, type(a))
如果調用的是類屬性, A.x 則轉換為:A.__dict__["x"].__get__(None, A)
其他情況見文末參考資料的文檔
__getitem__ 方法這個調用也屬于無條件調用,這點與 __getattribute__ 一致。區別在于 __getitem__ 讓類實例允許 [] 運算,可以這樣理解:
__getattribute__ 適用于所有 . 運算符;
__getitem__ 適用于所有 [] 運算符。
class A(object): a = 1 def __getitem__(self, item): print("__getitem__ call") return item t = A() print(t["a"]) print(t["b"])
如果僅僅想要對象能夠通過 [] 獲取對象屬性可以簡單的:
def __getitem(self, item): return object.__getattribute__(self, item)總結
當這幾個方法同時出現可能就會擾亂你了。我在網上看到一份示例還不錯,稍微改了下:
class C(object): a = "abc" def __getattribute__(self, *args, **kwargs): print("__getattribute__() is called") return object.__getattribute__(self, *args, **kwargs) # return "haha" def __getattr__(self, name): print("__getattr__() is called ") return name + " from getattr" def __get__(self, instance, owner): print("__get__() is called", instance, owner) return self def __getitem__(self, item): print("__getitem__ call") return object.__getattribute__(self, item) def foo(self, x): print(x) class C2(object): d = C() if __name__ == "__main__": c = C() c2 = C2() print(c.a) print(c.zzzzzzzz) c2.d print(c2.d.a) print(c["a"])
可以結合輸出慢慢理解,這里還沒涉及繼承關系呢。總之,每個以 __ get 為前綴的方法都是獲取對象內部數據的鉤子,名稱不一樣,用途也存在較大的差異,只有在實踐中理解它們,才能真正掌握它們的用法。
參考https://docs.python.org/3/ref...
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/45005.html
摘要:區別遍歷數組常用調用數組的每個元素,并將元素傳遞給回調函數這種循環的問題在于無法中途跳出循環,和命令不能奏效和都返回數組,返回的與原數組長度相同只返回符合條件的結果一個值和返回布爾值遍歷對象所有的可枚舉屬性主要是為了遍歷對象而設計的,不適 forEach,map,filter區別 forEach 遍歷數組常用(調用數組的每個元素,并將元素傳遞給回調函數) let arr = [1,2...
摘要:四通過跨域一個頁面嵌入一個外域的頁面雖然兩個窗體之前能獲取彼此的對象,但是卻拿不到上的屬性和方法,例如一個頁面嵌入一個的我是父窗體的方法嵌入的窗體跟的域名不同,很明顯是跨域的,雖然能獲取到對象,但是拿不到頁面的任何方法和屬性。 js跨域是指通過js在不同域之間進行相互通信或者數據傳輸,只要協議,域名,端口號其中有一個不同,就是跨域。下面總結一下我了解到的常用的跨域方法。 一:通過jso...
摘要:類和的背景顏色都為白色大于號指子代元素子代選擇器類下的類元素的背景顏色為白色空格指后代元素后代選擇器類下的所有類元素的背景顏色為白色與子代選擇器不同,后代選擇器可以包含下的所有元素,包括子孫加號指相鄰元素相鄰選擇器緊接在類下的類元素的 類a和b的背景顏色都為白色 大于號‘ > ’指子代元素(子代選擇器) .a>.b{ background-color:#fff; } 類a下的類...
摘要:說一說迭代器通過集合對象獲取其對應的對象判斷是否存在下一個元素取出該元素并將迭代器對象指向下一個元素取出元素的方式迭代器。對于使用容器者而言,具體的實現不重要,只要通過容器獲取到該實現的迭代器的對象即可,也就是方法。 前言 歡迎關注微信公眾號:Coder編程獲取最新原創技術文章和相關免費學習資料,隨時隨地學習技術知識!** 本章主要介紹Collection集合相關知識,結合面試中會提到...
摘要:面試題答案領取方式見主頁的缺省端口是多少,怎么修改有哪幾種運行模式優化有幾種部署方式容器是如何創建類實例用到了什么原理如何優化內存怎樣調優垃圾回收怎樣策略調優怎樣共享處理怎樣添加遠程監控專業點的分析工具有哪些關于的數目怎樣監視的內存使用情況 TomcatshowImg(https://segmentfault.com/img/remote/1460000019788819);(面試題+...
閱讀 1411·2021-10-11 11:12
閱讀 3244·2021-09-30 09:46
閱讀 1633·2021-07-28 00:14
閱讀 3132·2019-08-30 13:49
閱讀 2581·2019-08-29 11:27
閱讀 3211·2019-08-26 11:52
閱讀 598·2019-08-23 18:14
閱讀 3435·2019-08-23 16:27