通过修饰符在python中缓存属性的结果

通过修饰符在python中缓存属性的结果,python,caching,decorator,python-decorators,Python,Caching,Decorator,Python Decorators,在我的场景中,我有一个具有许多属性的类。这些属性不接受任何参数,计算时间很长,并且在程序生命周期中其结果不应更改 我希望缓存这些属性的结果,因此繁重的计算只需执行一次。我采用的方法是使用装饰师: def cached(f): def wrapper(*args): # get self class_self = args[0] cache_attr_name = '_' + f.__name__ if hasattr(cl

在我的场景中,我有一个具有许多属性的类。这些属性不接受任何参数,计算时间很长,并且在程序生命周期中其结果不应更改

我希望缓存这些属性的结果,因此繁重的计算只需执行一次。我采用的方法是使用装饰师:

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

对于这种情况,有没有更好的/其他解决方案

对于Python 3.8,使用内置的
cached\u属性

对于旧版本,请使用库

或者使用以下代码:

类缓存的\u属性(对象):
"""
每个实例只计算一次,然后替换自身的属性
使用普通属性。删除该属性将重置属性。
基于https://github.com/pydanny/cached-property/blob/master/cached_property.py
"""
定义初始化(self,func):
self.\uuuuu doc\uuuuu=func.\uuuuu doc__
self.func=func
def缓存的_属性_包装(self、obj、_cls):
如果obj为无:
回归自我
value=obj.\uuuu dict\uuuu[self.func.\uuuuuu name\uuuuu]=self.func(obj)
返回值
__获取\uuuu=缓存的\u属性\u包装器

对于Python3.8,请使用内置的
cached\u属性

对于旧版本,请使用库

或者使用以下代码:

类缓存的\u属性(对象):
"""
每个实例只计算一次,然后替换自身的属性
使用普通属性。删除该属性将重置属性。
基于https://github.com/pydanny/cached-property/blob/master/cached_property.py
"""
定义初始化(self,func):
self.\uuuuu doc\uuuuu=func.\uuuuu doc__
self.func=func
def缓存的_属性_包装(self、obj、_cls):
如果obj为无:
回归自我
value=obj.\uuuu dict\uuuu[self.func.\uuuuuu name\uuuuu]=self.func(obj)
返回值
__获取\uuuu=缓存的\u属性\u包装器

为什么使用decorator而不是直接函数调用?我通常会选择显式选项,检查
\u heavy\u prop
是否为
None
(在这种情况下,属性将计算其值并将其存储在
\u heavy\u prop
)并返回它。是否有时你不得不使你的缓存失效?以@sim为基础进行构建是一个很好的选择;您可以定义一个类变量,该变量应包含
heavy_prop
的特定值,如果调用
MyClass.heavy_prop()
时未设置该值,则应立即设置该变量。@sim我不需要使缓存无效。您的建议是在MyClass的构造函数中定义一个新成员
\u heavy\u prop=None
,而不是像我一样在装饰器中动态添加它?@macr0controller:的确,这是我的建议。在这种情况下,代码的读者会更清楚地看到正在发生的事情。当然,你要付出“代价”,你必须写一个检查你的“受保护”属性(例如
\u heavy\u prop
)是否在每个属性中都是
None
。为什么你要使用decorator而不是直接函数调用?我通常会选择显式选项,检查
\u heavy\u prop
是否是
None
(在这种情况下,属性将计算其值并将其存储在
\u heavy\u prop
中)如果调用
MyClass.heavy\u prop()时未设置值,则可以定义一个类变量,该变量应包含
heavy\u prop
的特定值
您应该在此时此地设置变量。@sim我不需要使缓存无效。您的建议是在MyClass的构造函数中定义一个新成员
\u heavy\u prop=None
,而不是像我那样动态地将其添加到装饰器中?@macr0controller:的确,这是我的建议。在这种情况下,我的建议更加明显您的代码的读者了解发生了什么。当然,您要付出“代价”,您必须编写一份检查,检查您的“受保护”属性(例如,
\u heavy\u prop
)是否在每个属性中都是