在Python中有這兩個魔法方法容易讓人混淆:__getattr__和getattribute。一般咱們會定義__getattr__而歷來不會定義getattribute,下面咱們來看看這兩個的區別。python
class MyClass: def __init__(self, x): self.x = x def __getattr__(self, item): print('{}屬性爲找到!'.format(item)) return None >>> obj = MyClass(1) >>> obj.x 1 >>> obj.y y屬性爲找到! None
咱們定義一個MyClass
類,設置一個實例屬性爲x,值爲1。obj
爲這個類的實例,獲取obj.x
返回1,而獲取obj.y
發現屬性找不到,緣由是obj的實例變量中不包含y,找不到某屬性時會調用__getattr__
方法。框架
**調用__getattr__詳細過程以下:**
obj.attr
code
obj.__getattr__
方法,若是用戶沒有定義或者仍是找不到,拋出AttributeError
異常,屬性查找失敗!class MyClass: def __init__(self, x): self.x = x >>> obj = MyClass(1) >>> obj.y AttributeError: 'MyClass' object has no attribute 'a'
如上代碼,沒有定義__getattr__魔法方法,又找不到屬性,就會拋出異常orm
當咱們調用對象的屬性時,首先會調用__getattribute__
魔法方法。對象
obj.x obj.__getattribute__(x)
如上代碼,這兩個代碼實際上是等價的。當__getattribute__
查找失敗,就會去調用__getattr__
方法。繼承
代碼演示遞歸
class MyClass: def __init__(self, x): self.x = x def __getattribute__(self, item): print('正在獲取屬性{}'.format(item)) return super(MyClass, self).__getattribute__(item) >>> obj = MyClass(2) >>> obj.x 正在獲取屬性x 2
咱們使用__getattribute__
魔法方法時,要返回父類的方法,否則很難寫對
下面代碼是一個陷阱,會產生無限遞歸get
class MyClass: def __init__(self, x): self.x = x def __getattribute__(self, item): print('正在獲取屬性{}'.format(item)) return self.item >>> obj = MyClass(2) >>> obj.x File "xxx", line 11, in __getattribute__ print('正在獲取屬性{}'.format(item)) RecursionError: maximum recursion depth exceeded while calling a Python object
上面的代碼看起來彷佛是對的,但卻調入了無限遞歸的陷阱,至關於it
def __getattribute__(self, item): print('正在獲取屬性{}'.format(item)) return self.__getattribute__(item)
要十分警戒。io
另外,內置的getattr和hasattr也會觸發這個魔法方法
>>> getattr(obj, 'x', None) 正在獲取屬性x 2 >>> hasattr(obj, 'x', None) 正在獲取屬性x True
class MyClass: x = 999 def __init__(self, x): self.x = x def __getattribute__(self, item): print('正在獲取屬性{}'.format(item)) return super(MyClass, self).__getattribute__(item)
上面代碼中,定義了一個類屬性x和一個實例屬性x,這兩個屬性同名,根據Python語法規則,當對象獲取屬性x的時候,首先會在實例屬性中尋找,若是找不到纔回去類屬性中查找
>>> obj = MyClass(2) >>> print(obj.x) 正在獲取屬性x 2 >>> del obj.x #刪除了實例屬性x >>> print(obj.x) #此時訪問的是類屬性 正在獲取屬性 999
這樣就能印證了上面所說__getattribute__
的查找順序。一般該方法在框架中可能會用到,通常狀況下無需使用。