目标是创建一个自定义 python 类,它允许延迟加载属性(这是一个相当常见的问题,有各种不同的解决方案),但只在延迟访问时运行昂贵的初始化步骤。这是一个例子:
class LazyDateModule()
def __init__(self, args):
self.args = args
self._expensive_date_attr = None
def _expensive_init():
time.sleep(10)
self._expensive_date_attr = date.today()
@memoize
def date_str():
return str(self._expensive_date_attr)
@memoize
def month_num():
return self._expensive_date_attr.month
在这个例子中,我的 @memoize
装饰器为我处理缓存步骤。
如果我在别处定义我的 LazyDateModule:
LDM = LazyDateModule()
如何仅在第一次访问任何记忆化属性方法时运行 _expensive_init()
?我试过这样的事情:
class LazyDateModule()
def __init__(self, args):
self.args = args
self._assembled = False
self._expensive_date_attr = None
def _expensive_init():
time.sleep(10)
self._expensive_date_attr = date.today()
self._assembled = True
@memoize
def date_str():
if self._assembled is False:
self._expensive_init()
return str(self._expensive_date_attr)
@memoize
def month_num():
if self._assembled is False:
self._expensive_init()
return self._expensive_date_attr.month
但这不是很干净。理想情况下,我希望这种行为处于类级别 — 但我在尝试覆盖 __getattr__
或 __getattribute__
时遇到了困难。另一个装饰器也可以。
如果上面的内容令人困惑,我很抱歉。如果我能以任何方式澄清它,请告诉我!
编辑 1: 我觉得上面的例子有点太简单了。假设我的 _expensive_init() 做了很多事情,而不是仅仅定义一个属性。
def _expensive_init(self):
time.sleep(5)
self._expensive_date_attr = date.today()
time.sleep(1)
# send a message to someone saying that this occurred
time.sleep(1)
# run a db call to update when this action occurred
etc...
理想情况下,此方法将处理各种不同的行为。
最佳答案
你有一个缓存装饰器memoize
,那么为什么不用它来缓存你的_expensive_date_attr
呢?顺便说一句,把它变成一个属性:
class LazyDateModule():
def __init__(self, args):
self.args = args
self._assembled = False
@memoize
@property
def _expensive_date_attr(self):
return date.today
@memoize
def date_str():
return str(self._expensive_date_attr)
@memoize
def month_num():
return self._expensive_date_attr.month
关于一流属性访问的 Python 自定义初始化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43592243/