【问题标题】:Memoization Handler记忆处理程序
【发布时间】:2011-03-23 13:53:44
【问题描述】:

创建一个像下面这样可以为您处理记忆过程的类是“好习惯”吗?记忆化的好处是如此之大(在某些情况下,像这个,其中它从 501003 到 1507 次函数调用以及从 1.409 到 0.006 秒的 CPU 时间在我的计算机上),这样的类似乎很有用。

但是,我只阅读了关于 eval() 用法的负面 cmets。 考虑到这种方法提供的灵活性,这种用法是否可以原谅?

这可以以丢失副作用为代价自动保存任何返回值。谢谢。

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

【问题讨论】:

  • 您在谈论“Python 装饰器”,而 memoization 对它们来说是一个绝妙的用途。而且它不需要 evals(部分是邪恶的;你没听错)。

标签: python dynamic-programming memoization


【解决方案1】:

您无需求助于eval即可记忆。

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

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)

【讨论】:

    【解决方案2】:

    eval 经常被误拼为evil,主要是因为在运行时执行“字符串”的想法充满了安全考虑。您是否充分地转义了代码?引号?还有许多其他恼人的头痛。您的 memoise 处理程序有效,但它确实不是 Python 的做事方式。 MAK 的方法更像 Pythonic。让我们尝试一些实验。

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

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

    除此之外,您的版本还需要对要记忆的函数进行包装,该函数应以字符串形式写入。太丑了MAK 的解决方案是干净的,因为“记忆过程”被封装在一个单独的函数中,可以方便地以不显眼的方式应用于任何昂贵的函数。这不是很 Pythonic。如果您有兴趣,我在我的 Python 教程http://nibrahim.net.in/self-defence/ 中有一些关于编写此类装饰器的详细信息。

    【讨论】:

      猜你喜欢
      • 2017-02-14
      • 1970-01-01
      • 1970-01-01
      • 2016-10-14
      • 2012-09-27
      • 2015-05-13
      • 1970-01-01
      • 2011-03-09
      • 2012-05-25
      相关资源
      最近更新 更多