python getattr|python中__getattr__与__getattribute__用法

时间:2020-10-31  来源: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异常

python getattr|python中__getattr__与__getattribute__用法

http://m.bbyears.com/jiaocheng/107957.html

推荐访问:
相关阅读 猜你喜欢
本类排行 本类最新