第一类属性访问

时间:2017-04-24 15:34:41

标签: python python-2.7 lazy-loading lazy-evaluation

目标是创建一个自定义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...

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

1 个答案:

答案 0 :(得分: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