【发布时间】:2012-02-24 20:47:02
【问题描述】:
我有一些任务要解决,目前最重要的部分是使脚本尽可能节省时间。我正在尝试优化的元素之一是在其中一个函数中进行记忆。
所以我的问题是:以下 3-4 种方法中哪一种是在 Python 中实现记忆的最有效/最快的方法?
我提供的代码仅作为示例 - 如果其中一种方法更有效,但不是我提到的情况,请分享你所知道的。
解决方案 1 - 使用外部范围的可变变量
此解决方案通常显示为示例记忆,但我不确定它的效率如何。我听说使用全局变量(在这种情况下,它是外部变量,而不是全局范围的变量)效率较低。
def main():
memo = {}
def power_div(n):
try:
return memo[n]
except (KeyError):
memo[n] = (n ** 2) % 4 # example expression, should not matter
return memo[n]
# extensive usage of power_div() here
解决方案 2 - 使用默认的可变参数
我在某处发现过去使用默认可变参数从外部范围传递变量,当 Python 首先在本地范围内搜索变量时,然后在全局范围内,跳过非本地范围(在这种情况下函数main()) 内的范围。因为默认参数仅在定义函数时才被初始化,并且只能在内部函数内部访问,也许它因此更有效?
def main():
def power_div(n, memo={}):
try:
return memo[n]
except (KeyError):
memo[n] = (n ** 2) % 4 # example expression, should not matter
return memo[n]
# extensive usage of power_div() here
或者也许以下版本(实际上是解决方案 1 和 2 的组合)更有效?
def main():
memo = {}
def power_div(n, memo=memo):
try:
return memo[n]
except (KeyError):
memo[n] = (n ** 2) % 4 # example expression, should not matter
return memo[n]
# extensive usage of power_div() here
解决方案 3 - 函数的属性
这是 Python 中另一个非常常见的 memoization 示例 - memoization 对象存储为函数本身的属性。
def main():
def power_div(n):
memo = power_div.memo
try:
return memo[n]
except (KeyError):
memo[n] = (n ** 2) % 4 # example expression, should not matter
return memo[n]
# extensive usage of power_div() here
总结
我对您对上述四种记忆化解决方案的意见非常感兴趣。同样重要的是,使用 memoization 的函数在另一个函数中。
我知道还有其他用于记忆的解决方案(例如Memoize decorator),但我很难相信这是比上面列出的更有效的解决方案。如果我错了,请纠正我。
提前致谢。
【问题讨论】:
-
与大多数“哪个更快”的问题一样,最终的答案是“尝试并找出答案”。
timeit模块提供了一种非常好的方法来测试这样的事情。 -
(另外:你有没有分析过你现有的代码并发现 memoization 是一个瓶颈?如果没有,你为什么要专注于优化它?)
-
@Amber:案例是1)我现有的代码没有太多需要优化的地方,所以我正在尽我所能改进,2)这个问题更多的是关于上述案例的效率为什么一个比另一个更好,它更普遍。我不想使用
timeit,因为 1) 我可能缺少其他一些更有效的解决方案。 2)由于我使用记忆的方式,我的结果可能有偏差。我正在尝试找到最快的方法来使用 memoization 来学习它并让人们知道,不一定要修复这段代码(这样的问题会过于本地化)。 -
我的直接假设是使用
dict对象的get()方法比捕获KeyError更快。但可能加速只会影响“缓存未命中”分支,在这种情况下不值得。但这可能值得双向计时。 -
@DanielPryden:我一直在考虑使用
get(),但是如果没有找到密钥,您需要计算一些东西,它看起来像:memo.get(n, (n ** 2) % 4)。在这种情况下,它没有多大意义,因为每次调用函数时都会执行(n ** 2) % 4(因此记忆化是无用的)。
标签: python performance argument-passing static-variables memoization