定義區(qū)別:
_getattr_(self, item)
獲取實(shí)例
的屬性時(shí)肴盏,僅當(dāng)實(shí)例屬性中不包括item時(shí)菜皂,才被調(diào)用厉萝。這個(gè)方法應(yīng)該返回相應(yīng)的屬性值或者拋出 AttributeError 異常_getattribute_(self, item)
獲取實(shí)例
屬性時(shí),無條件調(diào)用該方法常侣,不論實(shí)例屬性中是否包括item
應(yīng)用實(shí)例
- 利用
__getattr__
結(jié)合遞歸實(shí)現(xiàn)url動(dòng)態(tài)生成器胳施,代碼來自于github-sinaweibopy
class UrlGenerator(object):
def __init__(self, root_url):
self.url = root_url
def __getattr__(self, item):
if item == 'get' or item == 'post':
print(self.url)
return UrlGenerator('{}/{}'.format(self.url, item))
url_gen = UrlGenerator('http://xxxx')
url_gen.users.show.get
http://xxxx/users/show
- 自己的django項(xiàng)目中舞肆,結(jié)合
__getattribute__
與decorator實(shí)現(xiàn)動(dòng)態(tài)獲取屬性椿胯。
myconf = MyConfClient()
def myconf_decorator(key):
"""
首先從myconf中獲取屬性key剃根,取不到再到origin_class取
"""
def wraper(origin_class):
# 定義被裝飾類origin_class的__getattribute__方法
def __getattribute__(self, item):
try:
# 首先從myconf中獲取屬性
return myconf.get_dict(key)[item]
except (CanNotGetConfError, KeyError):
try:
# myconf中不存在屬性key時(shí)狈醉,再從origin_class中查找
return self.item
except KeyError:
raise CanNotGetConfError('key: %s item: %s' % (key, item))
origin_class.__getattribute__ = __getattribute__
return origin_class()
return wraper
在寫這個(gè)裝飾器的過程中苗傅,出現(xiàn)了無限遞歸的情況T健逊桦!
RecursionError: maximum recursion depth exceeded while calling a Python object
_getattribute_無限遞歸
__getattribute__
: 是無條件被調(diào)用强经。對任何對象的屬性訪問時(shí),都會(huì)隱式的調(diào)用__getattribute__
方法,比如調(diào)用t.__dict__
夕凝,其實(shí)執(zhí)行了t.__getattribute__("__dict__")
方法.
例如存在類A宝穗,a是A的一個(gè)實(shí)例户秤,當(dāng)我們通過a.x
獲取屬性值時(shí),實(shí)際的過程:
- 如果類A中重載了
__getattribute__
逮矛,則調(diào)用__getattribute
- 沒有重載
__getattribute__
鸡号,則調(diào)用a.\__dict__[x]
- 調(diào)用
A.\__dict__[x]
或者A.\__base__.__dict[x]
所以按照上面的寫法,我們在a.x時(shí)须鼎,調(diào)用__getattribute__
方法鲸伴,而該方法中使用self.key
,相當(dāng)于再次調(diào)用__getattribute__
晋控,造成無限遞歸汞窗。或者我們在重載__getattribute__
中又調(diào)用__dict__
的話赡译,也會(huì)無限遞歸仲吏。
so裹唆,解決方法,在__getatribute__
方法中成畦,調(diào)用object.__getattribute__
,切斷無限遞歸:
def __getattribute__(self, item):
try:
# 首先從myconf中獲取屬性
return myconf.get_dict(key)[item]
except (CanNotGetConfError, KeyError):
try:
# myconf中不存在屬性key時(shí)存和,再從origin_class中查找
return super(origin_class, self).__getattribute__(item)
except (KeyError, AttributeError):
raise CanNotGetConfError('key: %s item: %s' % (key, item))
而且如果沒有重載__getattr__
方法時(shí),__getattribute__
方法中需要處理AttributeError異常