Python设计模式-惰性计算/延迟计算(Lazy Evaluation)

惰性计算/延迟计算(Lazy Evaluation)

目的:类的某个属性来自于一个复杂的耗时的计算,但并不是每次都会调用。通过lazy evaluation模式,可以使该值只在真正需要读取的时候才进行一次计算

返回 Python设计模式-outline

示例

import functools

class lazy_property:
    '''一种 lazy property类装饰器'''
    def __init__(self, function):
        self.function = function
        functools.update_wrapper(self, function)

    def __get__(self, obj, type_):
        if obj is None:
            return self
        val = self.function(obj)
        obj.__dict__[self.function.__name__] = val
        return val

def lazy_property2(fn):
    '''一种 lazy propety函数装饰器'''
    attr = "_lazy__" + fn.__name__
    
    @property
    def _lazy_property(self):
        if not hasattr(self, attr):
            setattr(self, attr, fn(self))
        return getattr(self, attr)

    return _lazy_property


class Person:
    def __init__(self, name, occupation):
        self.name = name
        self.occupation = occupation
        self.call_count2 = 0

    # 这个装饰器,使Person.relatives可以当做属性来调用,并且,只有在第一次调用的时候会进行一次计算,调用前并不使用计算资源。从从而达到提高性能的目的。
    @lazy_property
    def relatives(self):
        # Get all relatives, let's assume that it costs much time.
        relatives = "Many relatives."
        return relatives

    @lazy_property2
    def parents(self):
        self.call_count2 += 1
        return "Father and mother"

# 调用
if __name__ == '__main__':
    Jhon = Person('Jhon', 'Coder')

    # 调用 Jhon.relatives之前,relatves函数并没有真正执行
    sorted(Jhon.__dict__.items())
    # 预期输出 [('call_count2', 0), ('name', 'Jhon'), ('occupation', 'Coder')]

    Jhon.relatives
    # 预期输出 'Many relatives.'

    # 调用 Jhon.relatives之后,relatves函数已执行并将结果保存到同名属性中
    sorted(Jhon.__dict__.items())
    # 预期输出  [('call_count2', 0), ..., ('relatives', 'Many relatives.')]

    # 调用 Jhon.parents之后,该函数被执行,并将结果保存到_lazy__parents中
    Jhon.parents
    # 预期输出 'Father and mother'

    sorted(Jhon.__dict__.items())
    # 预期输出 [('_lazy__parents', 'Father and mother'), ('call_count2', 1), ..., ('relatives', 'Many relatives.')]
    # 从 call_count2 == 1 可以看出,parents被调用了一次

    # 再次调用 Jhon.parents,parents函数不会被执行,仅仅是从已有的_lazy__parents中取出结果。
    Jhon.parents
    # 预期输出 'Father and mother'

    sorted(Jhon.__dict__.items())
    Jhon.call_count2
    # 预期输出 1

ref

https://blog.csdn.net/qq_23981335/article/details/102474702

https://en.wikipedia.org/wiki/Lazy_evaluation

bottle
https://github.com/bottlepy/bottle/blob/cafc15419cbb4a6cb748e6ecdccf92893bb25ce5/bottle.py#L270
django
https://github.com/django/django/blob/ffd18732f3ee9e6f0374aff9ccf350d85187fac2/django/utils/functional.py#L19
pip
https://github.com/pypa/pip/blob/cb75cca785629e15efb46c35903827b3eae13481/pip/utils/init.py#L821
pyramid
https://github.com/Pylons/pyramid/blob/7909e9503cdfc6f6e84d2c7ace1d3c03ca1d8b73/pyramid/decorator.py#L4
werkzeug
https://github.com/pallets/werkzeug/blob/5a2bf35441006d832ab1ed5a31963cbc366c99ac/werkzeug/utils.py#L35

posted @   坦先生的AI资料室  阅读(323)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 25岁的心里话
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示