记忆处理程序

发布于 2024-09-12 10:00:16 字数 1189 浏览 8 评论 0原文

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

但是,我只读过关于使用 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()')

Is it "good practice" to create a class like the one below that can handle the memoization process for you? The benefits of memoization are so great (in some cases, like this one, where it drops from 501003 to 1507 function calls and from 1.409 to 0.006 seconds of CPU time on my computer) that it seems a class like this would be useful.

However, I've read only negative comments on the usage of eval(). Is this usage of it excusable, given the flexibility this approach offers?

This can save any returned value automatically at the cost of losing side effects. Thanks.

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

昇り龍 2024-09-19 10:00:16

您无需求助于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)

You can memoize without having to resort to eval.

A (very basic) 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)
终难愈 2024-09-19 10:00:16

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/自卫/如果你有兴趣的话。

eval is often misspelt as evil primarily because the idea of executing "strings" at runtime is fraught with security considerations. Have you escaped the code sufficiently? Quotation marks? And a host of other annoying headaches. Your memoise handler works but it's really not the Python way of doing things. MAK's approach is much more Pythonic. Let's try a few experiments.

I edited up both the versions and made them run just once with 100 as the input. I also moved out the instantiation of Memoizer.
Here are the results.

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

In addition to this, your version necessitates a wrapper around the the function to be memoised which should be written in a string. That's ugly. MAK's solution is clean since the "process of memoisation" is encapsulated in a separate function which can be conveniently applied to any expensive function in an unobtrusive fashion. This is not very Pythonic. I have some details on writing such decorators in my Python tutorial at http://nibrahim.net.in/self-defence/ in case you're interested.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文