__getattribute__官方文檔中描述如下: 該方法可以攔截對對象屬性的所有訪問企圖,,當(dāng)屬性被訪問時,,自動調(diào)用該方法(只適用于新式類)。因此常用于實現(xiàn)一些訪問某屬性時執(zhí)行一段代碼的特性,。 需要注意的是,,正式由于它攔截對所有屬性的訪問(包括對__dict__的訪問),在使用中要十分小心地避開無限循環(huán)的陷阱,。在__getattribute__方法中訪問當(dāng)前實例的屬性時,,唯一安全的方式是使用基類(超類) 的方法__getattribute__(使用super)。例如: 通過上圖中的代碼示例可以看出,,一旦實現(xiàn)了__getattribute__方法,,所有通過對象訪問的屬性(包括類屬性)都會被攔截,而直接通過類訪問類屬性則不會,。 注意:當(dāng)訪問的屬性不存在并重載(覆蓋基類對某方法的默認(rèn)實現(xiàn))了__getattribute__方法時,,該方法不會主動拋出AttributeError異常。上圖中捕獲的AttributeError異常,,是由基類__getattribute__方法實現(xiàn)并拋出,。 常見的錯誤用法示例: 在實現(xiàn)__getattribute__方法時訪問對象自身的屬性,程序陷入無限循環(huán)直到崩潰,。 __getattr__官方文檔描述如下: __getattr__方法的自動執(zhí)行,,需要滿足兩個條件:一是訪問對象屬性;二是觸發(fā)AttributeError異常,。代碼示例如下: 上圖中,,調(diào)用不存在的job屬性首先調(diào)用__getattribute__方法(如果該方法未定義,會調(diào)用基類的__getattribute__方法),,觸發(fā)AttributeError異常并自動捕獲,,然后才調(diào)用__getattr__方法,。 錯誤用法示例如下: 重載了__getattribute__方法,卻沒有主動拋出AttributeError異常的機(jī)制,,或者拋出一個其它類型的異常,,__getattr__方法都不會執(zhí)行。 __setattr__試圖給屬性賦值時自動調(diào)用該方法,,例如: 之所以會執(zhí)行三次print函數(shù),,是因為在__init__方法中,對象A初始化時給屬性name和age賦值時,,觸發(fā)了__setattr__方法,。使用該方法是同樣需要十分小心避免無限循環(huán)陷阱。 錯誤用法示例如下: 可以看出,,在__setattr__方法中,,不能直接給屬性賦值,而通常的做法是使用__dict__魔法屬性,。__dict__屬性是一個字典,,所有的實例屬性都存儲在這個字典中,而修改__dict__字典中的鍵值對成員不會觸發(fā)__setattr__方法,,這里應(yīng)注意與直接修改__dict__的值的區(qū)別,。 注意:如果定義__setattr__方法的同時定義了__getattribute__方法,那么在修改__dict__字典中的鍵值對時,,由于調(diào)用了self.__dict__屬性,,同樣會觸發(fā)__getattribute__方法,使用時應(yīng)格外小心,。代碼示例如下: 上圖示例代碼中,,每調(diào)用一次__setattr__就會調(diào)用一次__getattribute__。 注意賦值語句與屬性調(diào)用的區(qū)別:self.__dict__ = {}是賦值語句,,不會觸發(fā)__getattribute__方法,,但觸發(fā)__setattr__方法;self.__dict__[name] = value語句,,先調(diào)用self.__dict__屬性,,得到dict對象后再修改其成員,因此會觸發(fā)__getattribute__方法,。 以上,。 |
|