【问题标题】:Cache results of properties in python through a decorator通过装饰器在python中缓存属性的结果
【发布时间】:2020-05-12 17:45:00
【问题描述】:

在我的场景中,我有一个包含许多属性的类。这些属性不带任何参数,它们的计算时间很长,并且它们的结果在程序生命周期内不应该改变。

我想缓存那些属性的结果,所以繁重的计算只进行一次。我采用的方法是使用装饰器:

def cached(f):
    def wrapper(*args):
        # get self
        class_self = args[0]
        cache_attr_name = '_' + f.__name__

        if hasattr(class_self, cache_attr_name):
            return getattr(class_self, cache_attr_name)

        else:
            result = f(*args)
            setattr(class_self, cache_attr_name, result)
            return result

    return wrapper

然后在缓存的类成员中:

class MyClass():
    @property
    @cached
    def heavy_prop(self):
        # In the actual class, the heavy calculation happens here
        return 1

对于这种情况的更好/其他解决方案有什么想法吗?

【问题讨论】:

  • 为什么使用装饰器而不是直接函数调用?
  • 我通常会选择显式选项来检查_heavy_prop 是否为None(在这种情况下,属性将计算其值并将其存储在_heavy_prop 中),否则返回它。是否也有必须使缓存失效的时候?
  • 以@sim 为基础是在谈论;你可以做的是定义一个类变量,它应该包含 heavy_prop 的特定值,如果在调用 MyClass.heavy_prop() 时没有设置该值,你应该在那里设置变量。
  • @sim 我不需要使缓存失效。您的建议是在 MyClass 的构造函数中定义一个新成员 _heavy_prop=None,而不是像我一样在装饰器中动态添加它?
  • @macr0controller:确实,这是我的建议。在这种情况下,您的代码的读者会更清楚正在发生的事情。当然,您要付出“代价”,您必须检查您的“protected”属性属性(例如_heavy_prop)在每个属性中是否为None

标签: python caching decorator python-decorators


【解决方案1】:

对于 Python 3.8,使用内置的cached_propertyhttps://docs.python.org/dev/library/functools.html#functools.cached_property

对于旧版本,请使用库 https://github.com/pydanny/cached-property

或者直接使用这个代码:

class cached_property(object):
    """
    A property that is only computed once per instance and then replaces itself
    with an ordinary attribute. Deleting the attribute resets the property.

    Based on https://github.com/pydanny/cached-property/blob/master/cached_property.py
    """

    def __init__(self, func):
        self.__doc__ = func.__doc__
        self.func = func

    def cached_property_wrapper(self, obj, _cls):
        if obj is None:
            return self

        value = obj.__dict__[self.func.__name__] = self.func(obj)
        return value

    __get__ = cached_property_wrapper

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-07-29
    • 2015-07-14
    • 2014-05-05
    • 2019-08-08
    • 2022-09-29
    • 2018-07-06
    • 2015-05-11
    相关资源
    最近更新 更多