【www.bbyears.com--python】
定义区别:
__getattr__(self, item) 获取实例的属性时,仅当实例属性中不包括item时,才被调用。这个方法应该返回相应的属性值或者抛出 AttributeError 异常
__getattribute__(self, item) 获取实例属性时,无条件调用该方法,不论实例属性中是否包括item
应用实例
1. 利用 __getattr__结合递归实现url动态生成器,代码来自于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
2. 自己 的django项目中,结合__getattribute__与decorator实现动态获取属性。
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时,再从origin_class中查找
return self.item
except KeyError:
raise CanNotGetConfError("key: %s item: %s" % (key, item))
origin_class.__getattribute__ = __getattribute__
return origin_class()
return wraper
在写这个装饰器的过程中,出现了无限递归的情况!!
RecursionError: maximum recursion depth exceeded while calling a Python object
__getattribute__无限递归
__getattribute__: 会无条件被调用。对任何对象的属性访问时,都会隐式的调用__getattribute__方法,比如调用t.__dict__,其实执行了t.__getattribute__("__dict__")方法.
例如存在类A,a是A的一个实例,当我们通过a.x获取属性值时,实际的过程:
如果类A中重载了__getattribute__,则调用__getattribute
没有重载__getattribute__,则调用a.\__dict__[x]
调用A.\__dict__[x]或者A.\__base__.__dict[x]
所以按照上面的写法,我们在a.x时,调用__getattribute__方法,而该方法中使用self.key,相当于再次调用__getattribute__,造成无限递归。或者我们在重载__getattribute__中又调用__dict__的话,也会无限递归。
so,解决方法,在__getatribute__方法中,调用object.__getattribute__,切断无限递归:
def __getattribute__(self, item):
try:
# 首先从myconf中获取属性
return myconf.get_dict(key)[item]
except (CanNotGetConfError, KeyError):
try:
# myconf中不存在属性key时,再从origin_class中查找
return super(origin_class, self).__getattribute__(item)
except (KeyError, AttributeError):
raise CanNotGetConfError("key: %s item: %s" % (key, item))
而且如果没有重载__getattr__方法时,__getattribute__方法中需要处理AttributeError异常