__get__,__getattr__和__getattribute__都是訪問屬性的方法,但不太相同。
object.__getattr__(self, name)
當(dāng)一般位置找不到attribute的時(shí)候,會(huì)調(diào)用__getattr__,返回一個(gè)值或AttributeError異常
object.__getattribute__(self, name)
無條件被調(diào)用,通過實(shí)例訪問屬性。如果class中定義了__getattr__(),則__getattr__()不會(huì)被調(diào)用(除非顯示調(diào)用或引發(fā)AttributeError異常)
object.__get__(self, instance, owner)
如果class定義了它,則這個(gè)class就可以稱為descriptor。owner是所有者的類,instance是訪問descriptor的實(shí)例,如果不是通過實(shí)例訪問,而是通過類訪問的話,instance則為None。(descriptor的實(shí)例自己訪問自己是不會(huì)觸發(fā)__get__,而會(huì)觸發(fā)__call__,只有descriptor作為其它類的屬性才有意義。)(所以下文的d是作為C2的一個(gè)屬性被調(diào)用)
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 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)
輸出結(jié)果是:
__getattribute__() is called
abc
__getattribute__() is called
__getattr__() is called
zzzzzzzz from getattr
__get__() is called <__main__.C2 object at 0x16d2310> <class '__main__.C2'>
__get__() is called <__main__.C2 object at 0x16d2310> <class '__main__.C2'>
__getattribute__() is called
abc
小結(jié):可以看出,每次通過實(shí)例訪問屬性,都會(huì)經(jīng)過__getattribute__函數(shù)。而當(dāng)屬性不存在時(shí),仍然需要訪問__getattribute__,不過接著要訪問__getattr__。這就好像是一個(gè)異常處理函數(shù)。
每次訪問descriptor(即實(shí)現(xiàn)了__get__的類),都會(huì)先經(jīng)過__get__函數(shù)。
需要注意的是,當(dāng)使用類訪問不存在的變量是,不會(huì)經(jīng)過__getattr__函數(shù)。而descriptor不存在此問題,只是把instance標(biāo)識(shí)為none而已。