通过修饰符在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
)是否在每个属性中都是无
。