python 再訪問屬性的方法上定義了__getattr__() 和 __getattribute__() 2種方法,其區別很是細微,但很是重要。python
__getattribute__()
方法,在 每次引用屬性或方法名稱時 Python 都調用它(特殊方法名稱除外,由於那樣將會致使討厭的無限循環)。__getattr__()
方法,Python 將只在正常的位置查詢屬性時纔會調用它。若是實例 x 定義了屬性 color, x.color
將 不會 調用x.__getattr__('color')
;而只會返回 x.color 已定義好的值。
讓咱們用兩個例子來解釋一下:編碼
>>> dyn = Dynamo() >>> dyn.color ③'PapayaWhip'>>> dyn.color = 'LemonChiffon' >>> dyn.color ④'LemonChiffon'class Dynamo(object): def __getattr__(self, key): if key == 'color': ① return 'PapayaWhip' else: raise AttributeError ②
__getattr()__
方法。若是名稱爲 'color'
,該方法返回一個值。(在此狀況下,它只是一個硬編碼的字符串,但能夠正常地進行某些計算並返回結果。)__getattr()__
方法必須引起一個 AttributeError
例外,不然在訪問未定義屬性時,代碼將只會默默地失敗。(從技術角度而言,若是方法不引起例外或顯式地返回一個值,它將返回 None
——Python 的空值。這意味着 全部 未顯式定義的屬性將爲 None
,幾乎能夠確定這不是你想看到的。)__getattr__()
。__getattr__()
方法,由於 dyn.color 已在該實例中定義。另外一方面,__getattribute__()
方法是絕對的、無條件的。spa
>>> dyn = SuperDynamo() >>> dyn.color ①'PapayaWhip'>>> dyn.color = 'LemonChiffon' >>> dyn.color ②'PapayaWhip'class SuperDynamo(object): def __getattribute__(self, key): if key == 'color': return 'PapayaWhip' else: raise AttributeError
__getattribute__()
方法。__getattribute__()
方法。若是存在 __getattribute__()
方法,將在每次查找屬性和方法時 無條件地調用 它,哪怕在建立實例以後已經顯式地設置了屬性。☞若是定義了類的
__getattribute__()
方法,你可能還想定義一個__setattr__()
方法,並在二者之間進行協同,以跟蹤屬性的值。不然,在建立實例以後所設置的值將會消失在黑洞中。code
必須特別當心 __getattribute__()
方法,由於 Python 在查找類的方法名稱時也將對其進行調用。htm
>>> hero = Rastan() >>> hero.swim() ②Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 3, in __getattribute__ AttributeErrorclass Rastan(object): def __getattribute__(self, key): raise AttributeError ① def swim(self): pass
AttributeError
例外的 __getattribute__()
方法。沒有屬性或方法的查詢會成功。hero.swim()
時,Python 將在 Rastan
類中查找 swim()
方法。該查找將執行整個 __getattribute__()
方法,由於全部的屬性和方法查找都經過__getattribute__()
方法。在此例中, __getattribute__()
方法引起 AttributeError
例外,所以該方法查找過程將會失敗,而方法調用也將失敗。