关于python:Memoization Handler

Memoization Handler

创建一个像下面这样的类来处理你的记忆过程,这是"好的实践"吗?memoization的好处是如此之大(在某些情况下,比如这一个,它从501003下降到1507个函数调用,在我的计算机上从1.409下降到0.006秒的CPU时间),以至于看起来像这样的类是有用的。

不过,我只看了关于eval()用法的负面评论。考虑到这种方法提供的灵活性,这种使用是否可以原谅?

这可以自动保存任何返回值,但会损失副作用。谢谢。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
import cProfile

class Memoizer(object):
   """A handler for saving function results."""
    def __init__(self):
        self.memos = dict()
    def memo(self, string):
        if string in self.memos:
            return self.memos[string]
        else:
            self.memos[string] = eval(string)
            self.memo(string)

def factorial(n):
    assert type(n) == int
    if n == 1:
        return 1
    else:
        return n * factorial(n-1)

# find the factorial of num
num = 500
# this many times
times = 1000

def factorialTwice():
    factorial(num)
    for x in xrange(0, times):
        factorial(num)
    return factorial(num)

def memoizedFactorial():
    handler = Memoizer()
    for x in xrange(0, times):
        handler.memo("factorial(%d)" % num)
    return handler.memo("factorial(%d)" % num)


cProfile.run('factorialTwice()')

cProfile.run('memoizedFactorial()')


你不用求助于eval就可以记忆。

一个(非常基本的)记忆器:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
def memoized(f):
    cache={}
    def ret(*args):
        if args in cache:
            return cache[args]
        else:
            answer=f(*args)
            cache[args]=answer
            return answer
    return ret

@memoized
def fibonacci(n):
    if n==0 or n==1:
        return 1
    else:
        return fibonacci(n-1)+fibonacci(n-2)

print fibonacci(100)

eval通常拼写错误为evil,主要是因为在运行时执行"字符串"的想法充满了安全考虑。您是否充分地避开了代码?引号?还有很多其他令人讨厌的头痛。您的Memoise处理程序可以工作,但它实际上不是Python的工作方式。Mak的方法更像是Python。让我们试试实验。

我编辑了两个版本,并让它们以100作为输入只运行一次。我还移动了Memoizer的实例化。这是结果。

1
2
3
4
>>> timeit.timeit(memoizedFactorial,number=1000)
0.08526921272277832h
>>> timeit.timeit(foo0.mfactorial,number=1000)
0.000804901123046875

除此之外,您的版本还需要在要Memoised的函数周围有一个包装器,该包装器应该写在一个字符串中。那太难看了。MAK的解决方案是干净的,因为"记忆过程"被封装在一个单独的功能中,可以方便地以一种不引人注目的方式应用于任何昂贵的功能。这不是很Python。在我的Python教程http://nibrahim.net.in/self-defense/中,我有一些关于编写此类装饰的详细信息,以防您感兴趣。