如何在Python中缓存/记忆对象?

时间:2017-02-15 08:33:36

标签: python caching

我有一些实例化的对象非常慢。它们表示从外部源(如YAML文件)加载的数据,并且加载大型YAML文件很慢(我不知道为什么)。

我知道这些对象取决于一些外部因素:

  • 在对象创建时传递的参数
  • 环境变量
  • 一些外部文件

理想情况下,如果外部因素相同,我想要一个透明的非样板方法来缓存这些对象:

@cache(depfiles=('foo',), depvars=(os.environ['FOO'],))
class Foo():
    def __init__(*args, **kwargs):
        with open('foo') as fd:
           self.foo = fd.read()
        self.FOO = os.environ['FOO']
        self.args = args
        self.kwargs = kwargs

主要思想是我第一次实例化Foo时,会使用对象的内容创建缓存文件,然后在下次实例化它时(在另一个Python会话中),缓存文件将是仅在依赖项和参数均未更改时使用。

到目前为止,我找到的解决方案基于shelve

import shelve

class Foo(object):
    _cached = False
    def __new__(cls, *args, **kwargs):
        cache = shelve.open('cache')
        cache_foo = cache.get(cls.__name__)
        if isinstance(cache_foo, Foo):
            cache_foo._cached = True
            return cache_foo
        self = super(Foo, cls).__new__(cls, *args, **kwargs)
        return self

    def __init__(self, *args, **kwargs):
        if self._cached:
            return

        time.sleep(2) # Lots of work
        self.answer = 42

        cache = shelve.open('cache')
        cache[self.__class__.__name__] = self
        cache.sync() 

它完美无缺,但它太样板,并没有涵盖所有情况:

  • 当不同的班级具有相同名称时发生冲突
  • 检查args和kwargs
  • 检查依赖项(环境变量,外部文件)

是否有任何 native 解决方案在Python中实现类似的行为?

1 个答案:

答案 0 :(得分:1)

Python 3提供functools.lru_cache()装饰器来提供可调用的memoization,但我认为你要求在你的应用程序的多次运行中保留缓存,到那时你有各种各样的不同要求。 '不太可能找到'一刀切'的解决方案。

如果您自己的答案适合您,请使用它。就“太多样板文件”而言,我会将缓存提取到一个单独的mixin类中:Foo__new__的第一个引用在任何情况下都可能应该是cls。您可以使用__qualname__属性而不是cls.__name__来减少类名冲突的可能性(假设Python 3.3或更高版本)。