2010-07-31 43 views
10

创建一个类似下面的类,可以为您处理记忆过程是“良好实践”吗? memoization的好处是如此之大(在某些情况下,就像这个,它从501003到1507函数调用以及从我的计算机上的1.409到0.006秒的CPU时间),看起来像这样的类会很有用。记忆处理程序

但是,我只读过eval()的使用负面评论。 鉴于此方法提供的灵活性,它是否可以使用?

这可以自动保存任何返回的值,其代价是失去副作用。谢谢。

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()') 
+0

你在谈论“Python装饰器”和memoization是他们的一个奇妙的用途。它不需要evals(这是部分邪恶的;你已经听到了正确的)。 – msw 2010-07-31 07:36:30

回答

13

您可以记住,而不必诉诸于eval

A(非常基本的)memoizer:

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) 
5

eval经常拼错为evil,主要是因为在运行时执行 “串” 的想法充满了安全方面的考虑。你有没有足够的逃避代码?引号?还有一些令人烦恼的头痛。你的记忆处理程序的作品,但它并不是Python的做事方式。 MAK的方法更为Pythonic。让我们尝试一些实验。

我编辑了两个版本,并使它们只用100次输入运行一次。我也搬出了Memoizer的实例。 以下是结果。

>>> timeit.timeit(memoizedFactorial,number=1000) 
0.08526921272277832h 
>>> timeit.timeit(foo0.mfactorial,number=1000) 
0.000804901123046875 

除此之外,你的版本需要一个围绕被记忆的函数的包装,它应该被写入一个字符串。这很丑陋。 MAK的解决方案是干净的,因为“memoisation”过程被封装在一个单独的功能中,可以方便地应用于任何昂贵的功能,而且不显眼。这不是Pythonic。如果您有兴趣,我可以在我的Python教程http://nibrahim.net.in/self-defence/上编写这样的装饰器。