使用重载装饰器的延迟加载变量

Seb*_*ian 5 python lazy-loading decorator

我有一个代表系统的状态对象.状态对象中的属性从[huge]文本文件中填充.因为每次创建状态实例时都不会访问每个属性,所以延迟加载它们是有意义的:

class State:
    def import_positions(self):
        self._positions = {}
        # Code which populates self._positions

    @property
    def positions(self):
        try:
            return self._positions
        except AttributeError:
            self.import_positions()
            return self._positions

    def import_forces(self):
        self._forces = {}
        # Code which populates self._forces

    @property
    def forces(self):
        try:
            return self._forces
        except AttributeError:
            self.import_forces()
            return self._forces
Run Code Online (Sandbox Code Playgroud)

这里有很多重复的样板代码.此外,有时import_abc可以填充一些变量(即,如果已经打开,则从一个小数据文件中导入一些变量).

重载@property是有意义的,它接受一个"提供"该变量的函数,即:

class State:
    def import_positions(self):
        self._positions = {}
        # Code which populates self._positions

    @lazyproperty(import_positions)
    def positions(self):
        pass

    def import_forces(self):
        self._forces = {}
        # Code which populates self._forces and self._strain

    @lazyproperty(import_forces)
    def forces(self):
        pass

    @lazyproperty(import_forces)
    def strain(self):
        pass
Run Code Online (Sandbox Code Playgroud)

但是,我似乎无法找到一种方法来准确追踪@property装饰器中正在调用的方法.因此,我不知道如何将@property重载到我自己的@lazyproperty中.

有什么想法吗?

lun*_*chs 3

也许你想要这样的东西。这是一种与@property.

def lazyproperty(func):
    values = {}
    def wrapper(self):
        if not self in values:
            values[self] = func(self)
        return values[self]
    wrapper.__name__ = func.__name__
    return property(wrapper)

class State:
    @lazyproperty
    def positions(self):
        print 'loading positions'
        return {1, 2, 3}

s = State()
print s.positions
print s.positions
Run Code Online (Sandbox Code Playgroud)

哪个打印:

loading positions
set([1, 2, 3])
set([1, 2, 3])
Run Code Online (Sandbox Code Playgroud)

警告:值字典中的条目不会被垃圾收集,因此它不适合长时间运行的程序。如果加载的值在所有类中都是不可变的,则可以将其存储在函数对象本身上,以获得更好的速度和内存使用:

try:
    return func.value
except AttributeError:
    func.value = func(self)
    return func.value
Run Code Online (Sandbox Code Playgroud)