2017-04-24 138 views
3

目标是创建一个自定义python类,它允许对属性进行延迟加载(这里有一个相当常见的问题,这里有各种不同的解决方案),但是一次只运行昂贵的初始化步骤懒惰的访问。这里有一个例子:对第一类属性访问的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() 

如何只在第一次任memoized属性方法进行访问运行_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... 

理想情况下,此方法将处理各种不同的行为。

+0

我写了一个类似的模块。我决定不完成它。它分两步工作。在第一步中,一个简单的方法装饰器通过向装饰函数本身添加一个属性来注册每个要记忆的方法。这个阶级本身并不存在,所以这就是它所能做到的。在第二步中,类装饰器检查所添加属性的所有方法,创建表,从类中移除这些方法,并安装一个自定义的__getattr__来捕获对表中名称的第一次访问,调用该函数并添加结果作为常规属性。希望能帮助到你。 – VPfB

回答

2

你有一个缓存修饰器memoize,那么为什么不用它来缓存你的_expensive_date_attr?和BTW把它变成一个属性:

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 
+0

为什么'date_str'和'month_num'应该被记忆呢? – VPfB

+0

没有其他原因,他们被记忆在你的代码 – Guillaume

+0

这是干净的,但不幸的是,我不认为这将适用于我所设想的。这方面的例子太简单了。查看我最近的更改。 – dizzyf