美文网首页
Python中实现lazy_property懒加载属性

Python中实现lazy_property懒加载属性

作者: 我只要喝点果粒橙 | 来源:发表于2022-04-02 10:49 被阅读0次

    看本文之前,可以先阅读Python中的lazy property,概念与用法在上述文章中有比较详细的介绍,本文是对其未讲解清晰地方的具体分析。

    描述符+类装饰器实现

    
    class LazyProperty(object):
        def __init__(self, func):
            # 初始化func为serverHost函数
            self.func = func
    
        def __get__(self, instance, owner):
            if instance is None:
                return self
            else:
                value = self.func(instance)
                # 会将结果值通过setattr方法存入到instance实例的__dict__中
                setattr(instance, self.func.__name__, value)
                return value
    
    
    class ConfigHandler:
        def __init__(self):
            pass
        # 返回一个LazyProperty实例 
        @LazyProperty
        def serverHost(self):
            return os.environ.get("HOST", setting.HOST)
    
    setting = namedtuple("setting", ["HOST"])
    setting.HOST = "g"
    
    # 测试一
    a = ConfigHandler()
    print(a.__dict__)
    # 1. 注解先是创建了LazyProperty(serverHost)的实例
    # 2. 再是语法糖进行了赋值serverHost = LazyProperty(serverHost)
    # 3. 当第一次进行调用的时候, instance = configHandler**实例**, self.func(instance实例) == 调用serverHost(instance实例)从而获得了真正值value。而之后的 setattr处将self实例的__dict__中添加了serverHost-value,再次访问self.serverHost时, 已经不再是函数, 而是value值(serverHost不再从ConfigHandler.__dict__中取, 而是实例a.__dict__中取)
    print(a.serverHost)
    print("say")
    print(a.__dict__)
    
    # 测试二
    # 如果先执行类的__dict__能看到类的serverHost是一个**描述器对象实例**=> 'serverHost': <__main__.LazyProperty object at 0x0000020A1AEB7FD0>
    print(ConfigHandler.__dict__)
    # 通过__dir__能见到serverHost为实例的一个方法
    print(a.__dir__())
    # 此时a.__dict__为空
    print(a.serverHost)
    # 等到调用过a.serverHost后可以发现a.__dict__中多了serverHost
    print(a.__dict__)
    # 由于实例__dict__会优先于类的__dict__使用,所以直接返回了value值
    

    重点:

    1. 跟[print(t.des)](#3.object.__get__(self, instance, owner))会触发t.des指向的descriptor实例的__get__一样,通过类__dict__["serverHost"],其也是个描述器实例,因此也会触发LazyProperty object的__get__
    2. 实例__dict__会优先于类的__dict__使用,如果实例__dict__找不到,会往上类__dict__

    修饰符(方法装饰器)

    def lazy_property(func):
        # 创建protected属性
        attr_name = "_lazy_" + func.__name__
        @property
        def _lazy_property(self):
            # print("done")
            if not hasattr(self, attr_name):
                # print("set")
                setattr(self, attr_name, func(self))
            return getattr(self, attr_name)
        return _lazy_property
    
    
    class Circle(object):
        def __init__(self, radius):
            self.radius = radius
    
        @lazy_property
        def area(self):
            return 3.14 * self.radius ** 2
    
    # 当解析Circle类、定义area方法的时候,会将Circle.area = @property修饰的_lazy_property函数
    c = Circle(4)
    print('before calculate area')
    print(c.__dict__)
    # 当调用c.area时,会输出done, 此时会执行_lazy_property内的具体函数, 此次会进行setattr
    print(c.area)
    # 此次不会调用setattr
    print(c.area)
    print('after calculate area')
    print(c.__dict__)
    c.radius = 5
    

    相关文章

      网友评论

          本文标题:Python中实现lazy_property懒加载属性

          本文链接:https://www.haomeiwen.com/subject/kgltsrtx.html