Python - __getattr__() 和 __getattribute__() 方法的區別

python 再訪問屬性的方法上定義了__getattr__() 和 __getattribute__() 2種方法,其區別很是細微,但很是重要。python

  1. 若是某個類定義了 __getattribute__() 方法,在 每次引用屬性或方法名稱時 Python 都調用它(特殊方法名稱除外,由於那樣將會致使討厭的無限循環)。
  2. 若是某個類定義了 __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 ②
  1. 屬性名稱以字符串的形式傳入 __getattr()__ 方法。若是名稱爲 'color',該方法返回一個值。(在此狀況下,它只是一個硬編碼的字符串,但能夠正常地進行某些計算並返回結果。)
  2. 若是屬性名稱未知, __getattr()__ 方法必須引起一個 AttributeError 例外,不然在訪問未定義屬性時,代碼將只會默默地失敗。(從技術角度而言,若是方法不引起例外或顯式地返回一個值,它將返回 None ——Python 的空值。這意味着 全部 未顯式定義的屬性將爲 None,幾乎能夠確定這不是你想看到的。)
  3. dyn 實例沒有名爲 color 的屬性,所以在提供計算值時將調用 __getattr__() 。
  4. 在顯式地設置 dyn.color 以後,將再也不爲提供 dyn.color 的值而調用 __getattr__() 方法,由於 dyn.color 已在該實例中定義。

另外一方面,__getattribute__() 方法是絕對的、無條件的。編碼

 >>> 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
  1. 在獲取 dyn.color 的值時將調用 __getattribute__() 方法。
  2. 即使已經顯式地設置 dyn.color,在獲取 dyn.color 的值時, 仍將調用 __getattribute__() 方法。若是存在 __getattribute__() 方法,將在每次查找屬性和方法時 無條件地調用 它,哪怕在建立實例以後已經顯式地設置了屬性。

☞若是定義了類的 __getattribute__() 方法,你可能還想定義一個 __setattr__() 方法,並在二者之間進行協同,以跟蹤屬性的值。不然,在建立實例以後所設置的值將會消失在黑洞中。spa

必須特別當心 __getattribute__() 方法,由於 Python 在查找類的方法名稱時也將對其進行調用。code

 >>> 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
  1. 該類定義了一個老是引起 AttributeError 例外的 __getattribute__() 方法。沒有屬性或方法的查詢會成功。
  2. 調用 hero.swim() 時,Python 將在 Rastan 類中查找 swim() 方法。該查找將執行整個 __getattribute__()方法,由於全部的屬性和方法查找都經過__getattribute__() 方法。在此例中, __getattribute__() 方法引起 AttributeError 例外,所以該方法查找過程將會失敗,而方法調用也將失敗。

  1. "__getattr__"將會在尋找不到合適的函數或者屬性時做爲默認被調用到。
  2. 一般來講,若是腳本即包含"__getattribute__" ,又包含"__getattr__"的時候,是不會調用到"__getattr__"的,但從上面的例子能夠看出,若是"__getattribute__"報錯,一樣會自動調用到"__getattr__"。
相關文章
相關標籤/搜索