Quantcast
Channel: CodeSection,代码区,Python开发技术文章_教程 - CodeSec
Viewing all articles
Browse latest Browse all 9596

__getattr__与__getattribute__

$
0
0
定义区别:

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


Viewing all articles
Browse latest Browse all 9596

Latest Images

Trending Articles