记忆处理程序
创建一个像下面这样的类来为您处理记忆过程是“好的做法”吗?记忆化的好处是如此之大(在某些情况下,就像这个一样,它从我的计算机上的 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您无需求助于
eval
即可进行记忆。一个(非常基本的)记忆器:
You can memoize without having to resort to
eval
.A (very basic) memoizer:
eval
经常被误拼为evil
,主要是因为在运行时执行“字符串”的想法充满了安全考虑。您是否充分逃脱了代码?引号?还有许多其他令人头痛的问题。你的 memoise 处理程序可以工作,但它实际上不是 Python 的处理方式。 MAK 的方法更加Pythonic。让我们尝试一些实验。我编辑了这两个版本,并以 100 作为输入,让它们仅运行一次。我还移出了
Memoizer
的实例化。这是结果。
除此之外,您的版本还需要对要记忆的函数进行包装,该包装应以字符串形式编写。那太丑了。 MAK 的解决方案很干净,因为“记忆过程”被封装在一个单独的函数中,该函数可以以不引人注目的方式方便地应用于任何昂贵的函数。这不是很Pythonic。我在我的 Python 教程中提供了一些关于编写此类装饰器的详细信息,网址为 http://nibrahim.net.in/自卫/如果你有兴趣的话。
eval
is often misspelt asevil
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.
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.