1

标题或多或少说明了一切:

我有一个函数,它在两个参数中接受对称输入,例如

def f(a1, a2):
    return heavy_stuff(abs(a1 - a2))

现在,我想介绍一些缓存方法。做这样的事情是否正确/pythonic/相当有效:

cache = {}
def g(a1, a2):
    fs =frozenset((tuple(a1), tuple(a2)))
    if fs not in cache:
        cache[fs] = f(a1, a2)
    return cache[fs]

或者会有更好的方法吗?

编辑: a1 和 a2 可能是 numpy 数组的行;这就是为什么我将它们分别包装在一个元组中。

4

1 回答 1

2

Python 总是计算你传递给函数的所有参数,然后才调用函数。换句话说,与大多数其他语言一样,Python 在其评估中是“急切的”(今天的主要例外可能是 Haskell,但这对您没有帮助;-)。

所以setdefault是一种非常不适合缓存的方法!每当你这样做

cache.setdefault(akey, f(x, y))

首先调用f(x, y),并使用其所有计算成本,然后可能将该计算的结果丢弃在地板上;这使得缓存完全无效。

相反,请始终按以下方式进行:

akey = whatever(x, y)
if akey not in cache:
    cache[akey] = f(x, y)
return cache[akey]

等等——还有一些其他可能的习语,特别是如果你知道那f永远不会回来None

result = cache.get(akey)
if result is None:
    result = cache[akey] = f(x, y)
return result

至于什么是适合whatever密钥计算的次要问题,鉴于您知道这f是对称的,我认为frozenset可能还可以;虽然(如果 和 的组件xy可比较的,以及可散列的——即它不适用于复数)您可能需要考虑

ta1 = tuple(a1)
ta2 = tuple(a2)
if ta1 > ta2: key = ta1, ta2
else: key = ta2, ta1

相对性能取决于比较 和 中的项目与散列的a1成本a2。无论如何,差异可能很小。

于 2010-04-03T22:36:22.773 回答