__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异常