在Python中智能缓存昂贵的对象

YXD*_*YXD 1 python caching memory-management

我按顺序有一个图像目录.通常我的代码将使用来自连续图像子集的数据(例如图像5-10),并且用于访问这些数据的天真选项是:

  1. 使用一种方法创建包装器对象,该方法在需要时加载图像并读取我的数据(例如像素值).这几乎没有内存开销,但速度很慢,因为每次都需要加载每个映像.

  2. 将所有图像存储在内存中.这将很快,但显然我们可以存储多少图像是有限制的.

我想找到:

  • 我可以通过某种方法定义如何读取与索引或路径对应的图像,然后允许我访问,比如说magic_image_collection[index]我不必担心它是否会在内存中返回对象或重新读取它.这将理想地将适当的图像或n最近访问的图像保存在存储器中.

tit*_*ito 5

__missing__如果密钥丢失,您可以扩展默认的dict和use 方法来调用加载函数:

class ImageDict(dict):
    def __missing__(self, key):
        self[key] = img = self.load(key)
        return img
    def load(self, key):
        # create a queue if not exist (could be moved to __init__)
        if not hasattr(self, '_queue'):
            self._queue = []
        # pop the oldest entry in the list and the dict
        if len(self._queue) >= 100:
            self.pop(self._queue.pop(0))
        # append this key as a newest entry in the queue
        self._queue.append(key)
        # implement image loading here and return the image instance
        print 'loading', key
        return 'Image for %s' % key
Run Code Online (Sandbox Code Playgroud)

并且输出(仅当密钥不存在时才发生加载.)

>>> d = ImageDict()
>>> d[3]
loading 3
'Image for 3'
>>> d[3]
'Image for 3'
>>> d['bleh']
loading bleh
'Image for bleh'
>>> d['bleh']
'Image for bleh'
Run Code Online (Sandbox Code Playgroud)

一个演变是仅存储dict中的N个最后一个元素,并清除最旧的条目.您可以通过保留用于订购的密钥列表来实现它.

  • 摆脱`__getitem__`并将加载重命名为`__missing__`,你应该没问题. (2认同)
  • 您在`__missing__`中要做的只是为键返回适当的值,或者引发异常。名为`__missing__`的`dict`代码将负责更新dict(您的类继承自该字典)。要增加对“后n个元素”的支持,请添加一个键列表作为成员,并在“ __missing__”中将键添加到列表的末尾。当列表超过n时,从列表和自身中弹出最早的(0')键。 (2认同)