用于修改可变参数的函数的Python memoization

时间:2014-02-07 00:28:04

标签: python mutable memoization

假设我有一个修改list参数和memoizer装饰器的函数,例如:

@memoizer
def add_1_to_list(list):
    for i in range(len(list)):
        list[i] += 1
    return list

在我的主程序中,我有

list = [1, 1, 1, 1]
add_1_to_list(list)
print list

如果我的memoizer类只缓存返回值并设置add_1_to_list以返回相同的值,那么当我第一次运行主程序时,它将打印[2, 2, 2, 2],而第二次,它将打印{ {1}},因为列表是可变的。

是否有任何解决方案可以让memoizer类检测到函数修改了一个参数,这样我们就能记下它并保存修改过的参数?通过在memoizer类中调用它之前和之后打印参数,我能够直观地看到它,但是在不知道参数是什么类型以及它们是否是可变/不可变的情况下,似乎很难测试参数是否已被修改

2 个答案:

答案 0 :(得分:1)

您的问题唯一可能的答案是不要。你正在使用memoization,不应该使用memoization。

只记忆没有副作用的功能,或者你要求麻烦。

  

是否有任何解决方案可以让memoizer类检测函数是否修改了参数?

记忆者没有责任检测可变性,程序员有责任决定是否将记事本应用于该功能。

  

这样我们可以记下它并保存修改过的参数

这听起来像是过于复杂的事情。此外,如果你“保存”修改过的参数,你最终会保留对它们的引用,防止它们被释放。

答案 1 :(得分:0)

不确定如何实现memoizer,但可以使用function参数作为缓存内存的关键字。类似的东西:

def memoizer(func):

    mem = {}

    def wrapped(lst):
        key = tuple(lst)
        if key not in mem:
            print 'Actually computing for input %s...' % lst
            mem[key] = []
            mem[key][:] = func(lst)
        lst[:] = mem[key]
        return mem[key]

    return wrapped

@memoizer
def add_1_to_list(list):
    for i in range(len(list)):
        list[i] += 1
    return list

# Case 1
lst = [1, 1, 1, 1]
print 'Given', lst
print add_1_to_list(lst)
print add_1_to_list(lst)
print 'Finally lst is:', lst

# Case 2
lst = [1, 1, 1, 1]
print 'Given', lst
print add_1_to_list(lst)
print 'Finally lst is:', lst

请注意mem[key][:]是必要的,因为add_1_to_list没有在内部创建新列表,因此我们需要复制结果。 lst[:] = mem[key]模仿add_1_to_list的行为,即修改给定的输入列表。

案例1的输出:

  

给出[1,1,1,1]

     

实际上计算输入[1,1,1,1] ......

     

[2,2,2,2]

     

实际上计算输入[2,2,2,2] ......

     

[3,3,3,3]

     

最后,我是:[3,3,3,3]

现在准备好一些缓存:

  

给出[1,1,1,1]

     

[2,2,2,2]

     

最后,我是:[2,2,2,2]