简体   繁体   English

修改可变参数的函数的Python备注

[英]Python memoization for functions that modify mutable arguments

Say I have a function that modifies a list argument and a memoizer decorator, such as: 假设我有一个修改列表参数和备注设计器的函数,例如:

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

In my main program, I have 在我的主程序中,我有

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

If my memoizer class only caches the return values and sets add_1_to_list to return the same value, then when I run the main program the first time, it will print [2, 2, 2, 2] , while the second time, it will print [1, 1, 1, 1] , since list is mutable. 如果我的备忘录类仅缓存返回值并将add_1_to_list设置为返回相同的值,那么当我第一次运行主程序时,它将打印[2, 2, 2, 2] 2,2,2,2 [2, 2, 2, 2] ,而第二次它将打印[1, 1, 1, 1] 1,1,1,1 [1, 1, 1, 1] ,因为list是可变的。

Are there any solutions to get a memoizer class to detect that the function modifies an argument, that way we can note it and save modified arguments? 是否有任何解决方案可以使回忆器类检测该函数是否修改了参数,这样我们就可以记录它并保存修改后的参数? I was able to see it visually by printing the argument before and after calling it in the memoizer class, but without knowing what type the arguments are and whether they are mutable/immutable, it seems difficult to test whether an argument has been modified or not. 我可以通过在备忘录程序类中调用参数前后打印参数来直观地看到它,但是在不知道参数是什么类型以及它们是否可变/不可变的情况下,似乎很难测试参数是否已被修改。

The only possible answer to your question is don't . 对您问题的唯一可能答案是“ 否” You are using memoization where memoization ought not be used. 您正在使用不应使用便笺的便笺。

Only memoize functions which have no side effects, or you're asking for trouble. 仅记住没有副作用的功能,否则您会遇到麻烦。

Are there any solutions to get a memoizer class to detect that the function modifies an argument? 是否有任何解决方案来获取备忘录程序类以检测该函数是否修改了参数?

It isn't the memoizer's responsibility to detect mutability, it is programmer's responsibility to decide whether or not to apply the memoizer to the function. 检测可变性不是回忆器的责任,而是决定是否将回忆器应用于功能的程序员的责任。

that way we can note it and save modified arguments 这样我们可以记录下来并保存修改后的参数

That sounds to me like over-complicating things. 在我看来,这听起来太复杂了。 Besides, if you "save" modified arguments, you end up keeping references to them, preventing them from being deallocated. 此外,如果“保存”已修改的参数,最终将保留对它们的引用,以防止它们被释放。

Not sure how your memoizer is implemented, but you can use the function argument as the key to your cache memory. 不确定备忘录的实现方式,但是可以将function参数用作高速缓存的键。 Something like: 就像是:

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

Note that mem[key][:] will be necessary as add_1_to_list does not create a new list internally, so we need to make a copy of the result. 请注意,由于add_1_to_list不会在内部创建新列表,因此必须使用mem[key][:] ,因此我们需要复制结果。 lst[:] = mem[key] mimics the behavior of add_1_to_list which is to modify the given input list. lst[:] = mem[key]模仿add_1_to_list的行为,该行为将修改给定的输入列表。

Output of Case 1: 情况1的输出:

Given [1, 1, 1, 1] 给定[1,1,1,1]

Actually computing for input [1, 1, 1, 1]... 实际计算输入[1,1,1,1] ...

[2, 2, 2, 2] [2,2,2,2]

Actually computing for input [2, 2, 2, 2]... 实际上计算输入[2,2,2,2] ...

[3, 3, 3, 3] [3,3,3,3]

Finally lst is: [3, 3, 3, 3] 最后的lst是:[3,3,3,3]

Now with some cache ready: 现在已准备好一些缓存:

Given [1, 1, 1, 1] 给定[1,1,1,1]

[2, 2, 2, 2] [2,2,2,2]

Finally lst is: [2, 2, 2, 2] 最后一个lst是:[2,2,2,2]

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM