python中的链式记忆器

2024-09-26 22:55:02 发布

您现在位置:Python中文网/ 问答频道 /正文

我已经有了一个很好用的回忆录。它使用pickle转储序列化输入并创建MD5散列作为键。函数结果非常大,存储为pickle文件,文件名为MD5 hash。当我一个接一个地调用两个记忆化函数时,memoizer将加载第一个函数的输出并将其传递给第二个函数。第二个函数将序列化它,创建MD5,然后加载输出。下面是一个非常简单的代码:

@memoize
def f(x):
    ...
    return y

@memoize
def g(x):
    ...
    return y

y1 = f(x1)
y2 = g(y1)

当对f求值时,y1从磁盘加载,然后在计算g时序列化它。有没有可能绕过这个步骤,把y1(即MD5散列)的密钥传递给g?如果g已经有这个密钥,它将从磁盘加载y2。如果没有,它将“请求”完整的y1来评估{}。在

编辑:

^{pr2}$

Tags: 文件函数return序列化文件名def密钥hash
1条回答
网友
1楼 · 发布于 2024-09-26 22:55:02

我认为你可以用一种自动的方式来做,但我通常认为最好是明确地说明“懒惰”的评价。因此,我将介绍一种向你的记忆化函数添加额外参数的方法:lazy。但我将简化助手,而不是文件、pickle和md5:

# I use a dictionary as storage instead of files
storage = {}

# No md5, just hash
def calculate_md5(obj):
    print('calculating md5 of', obj)
    return hash(obj)

# create dictionary entry instead of pickling the data to a file
def create_file(md5, data):
    print('creating file for md5', md5)
    storage[md5] = data

# Load dictionary entry instead of unpickling a file
def load_file(md5):
    print('loading file with md5 of', md5)
    return storage[md5]

我使用自定义类作为中间对象:

^{pr2}$

最后,我展示了更改后的Memoize,假设您的函数只接受一个参数:

class Memoize(object):
    def __init__(self, func):
        self.func = func
        # The md5 to md5 storage is needed to find the result file 
        # or result md5 for lazy evaluation.
        self.md5_to_md5_storage = {}

    def __call__(self, x, lazy=False):
        # If the argument is a memoized object no need to
        # calculcate the hash, we can just look it up.
        if isinstance(x, MemoizedObject):
            key = x.md5
        else:
            key = calculate_md5(x)

        if lazy and key in self.md5_to_md5_storage:
            # Check if the key is present in the md5 to md5 storage, otherwise
            # we can't be lazy
            return MemoizedObject(self.md5_to_md5_storage[key])
        elif not lazy and key in self.md5_to_md5_storage:
            # Not lazy but we know the result
            result = load_file(self.md5_to_md5_storage[key])
        else:
            # Unknown argument
            result = self.func(x)
            result_md5 = calculate_md5(result)
            create_file(result_md5, result)
            self.md5_to_md5_storage[key] = result_md5
        return result

现在,如果调用函数并在正确的位置指定lazy,则可以避免加载(取消拾取)文件:

@Memoize
def f(x):
    return x+1

@Memoize
def g(x):
    return x+2

正常(首次)运行:

>>> x1 = 10
>>> y1 = f(x1)
calculating md5 of 10
calculating md5 of 11
creating file for md5 11
>>> y2 = g(y1)
calculating md5 of 11
calculating md5 of 13
creating file for md5 13

没有lazy

>>> x1 = 10
>>> y1 = f(x1)
calculating md5 of 10
loading file with md5 of 11
>>> y2 = g(y1)
calculating md5 of 11
loading file with md5 of 13

使用lazy=True

>>> x1 = 10
>>> y1 = f(x1, lazy=True)
calculating md5 of 10
>>> y2 = g(y1)
loading file with md5 of 13

最后一个选项只计算第一个参数的“md5”,并加载最终结果的文件。那应该正是你想要的。在

相关问题 更多 >

    热门问题