使用joblib仅缓存类的某些方法的正确方法

mwa*_*kom 7 python memoization joblib

我正在编写一个类,它有一些计算量很大的方法和一些用户希望迭代调整并且与计算无关的参数.

实际用途是用于可视化,但这是一个卡通示例:

class MyClass(object):

    def __init__(self, x, name, mem=None):

        self.x = x
        self.name = name
        if mem is not None:
            self.square = mem.cache(self.square)

    def square(self, x):
        """This is the 'computation heavy' method."""
        return x ** 2

    def report(self):
        """Use the results of the computation and a tweakable parameter."""
        print "Here you go, %s" % self.name
        return self.square(self.x)
Run Code Online (Sandbox Code Playgroud)

基本思想是用户可能希望使用相同x但不同的name参数创建此类的许多实例.我想允许用户提供一个joblib.Memory将缓存计算部分的对象,这样他们就可以"报告"许多不同的名称,而无需每次重新计算平方数组.

(我知道这有点奇怪.用户需要为每个名称设置不同的类实例的原因是他们实际上正在与看起来像这样的接口函数进行交互.

def myfunc(x, name, mem=None):
    theclass = MyClass(x, name, mem)
    theclass.report()
Run Code Online (Sandbox Code Playgroud)

但是现在让我们忽略它.


joblib文档之后,我square使用该行缓存该函数self.square = mem.cache(self.square).问题在于,因为self对于不同的实例会有所不同,所以即使参数相同,每次都会重新计算数组.

我猜测处理这个问题的正确方法是将线路更改为

self.square = mem.cache(self.square, ignore=["self"])
Run Code Online (Sandbox Code Playgroud)

但是,这种方法有什么缺点吗?有没有更好的方法来完成缓存?

Jos*_*ton 1

文档中,

如果您想在类中使用缓存,建议的模式是缓存纯函数并在类中使用缓存的函数。

由于您希望内存缓存是可选的,因此我建议如下:

def square_function(x):
    """This is the 'computation heavy' method."""
    print '    square_function is executing, not using cached result.'
    return x ** 2

class MyClass(object):

    def __init__(self, x, name, mem=None):
        self.x = x
        self.name = name
        if mem is not None:
            self._square_function = mem.cache(square_function)
        else:
            self._square_function = square_function

    def square(self, x):
        return self._square_function(x)

    def report(self):
        print "Here you go, %s" % self.name
        return self.square(self.x)


from tempfile import mkdtemp
cachedir = mkdtemp()

from joblib import Memory
memory = Memory(cachedir=cachedir, verbose=0)

objects = [
    MyClass(42, 'Alice (cache)', memory),
    MyClass(42, 'Bob (cache)', memory),
    MyClass(42, 'Charlie (no cache)')
]

for obj in objects:
    print obj.report()
Run Code Online (Sandbox Code Playgroud)

执行产量:

def square_function(x):
    """This is the 'computation heavy' method."""
    print '    square_function is executing, not using cached result.'
    return x ** 2

class MyClass(object):

    def __init__(self, x, name, mem=None):
        self.x = x
        self.name = name
        if mem is not None:
            self._square_function = mem.cache(square_function)
        else:
            self._square_function = square_function

    def square(self, x):
        return self._square_function(x)

    def report(self):
        print "Here you go, %s" % self.name
        return self.square(self.x)


from tempfile import mkdtemp
cachedir = mkdtemp()

from joblib import Memory
memory = Memory(cachedir=cachedir, verbose=0)

objects = [
    MyClass(42, 'Alice (cache)', memory),
    MyClass(42, 'Bob (cache)', memory),
    MyClass(42, 'Charlie (no cache)')
]

for obj in objects:
    print obj.report()
Run Code Online (Sandbox Code Playgroud)