Python 惰性求值器
是否有一种 Pythonic 方法来封装惰性函数调用,即在第一次使用函数 f()
时,它调用先前绑定的函数 g(Z)
并在连续调用 f()
返回缓存值?
请注意,记忆可能并不完美。
我有:
f = g(Z)
if x:
return 5
elif y:
return f
elif z:
return h(f)
该代码可以工作,但我想对其进行重组,以便仅在使用该值时才调用 g(Z)
。我不想更改 g(...)
的定义,而且 Z
有点大,无法缓存。
编辑:我认为 f
必须是一个函数,但情况可能并非如此。
Is there a Pythonic way to encapsulate a lazy function call, whereby on first use of the function f()
, it calls a previously bound function g(Z)
and on the successive calls f()
returns a cached value?
Please note that memoization might not be a perfect fit.
I have:
f = g(Z)
if x:
return 5
elif y:
return f
elif z:
return h(f)
The code works, but I want to restructure it so that g(Z)
is only called if the value is used. I don't want to change the definition of g(...)
, and Z
is a bit big to cache.
EDIT: I assumed that f
would have to be a function, but that may not be the case.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
我有点困惑你是否寻求缓存或惰性评估。对于后者,请查看 Alberto Bertogli 的 lazy.py 模块。
I'm a bit confused whether you seek caching or lazy evaluation. For the latter, check out the module lazy.py by Alberto Bertogli.
尝试使用这个装饰器:(
从死链接中提取:http://snippets.dzone.com/posts /show/4840 / https://web.archive.org/web/20081026130601/http://snippets.dzone.com/posts/show/4840)
(在这里找到:是否有一个装饰器来简单地缓存函数返回值?作者:Alex Martelli)
编辑:这是另一个属性形式的(使用
__get__
)http://code.activestate.com/recipes/363602/Try using this decorator:
(extracted from dead link: http://snippets.dzone.com/posts/show/4840 / https://web.archive.org/web/20081026130601/http://snippets.dzone.com/posts/show/4840)
(Found here: Is there a decorator to simply cache function return values? by Alex Martelli)
EDIT: Here's another in form of properties (using
__get__
) http://code.activestate.com/recipes/363602/好奇为什么在这种情况下不直接使用 lambda ?
Curious why you don't just use a lambda in this scenario?
您可以使用缓存装饰器,让我们看一个示例
使用缓存装饰器,在这里您可以编写
正如您从输出中看到的那样,
foo 将仅被调用一次。您不必更改函数 foo 的任何行。这就是装饰器的力量。
You can employ a cache decorator, let see an example
With the cache decorator, here you can write
As you can see from the output
The foo will be called only once. You don't have to change any line of your function foo. That's the power of decorators.
有很多用于记忆的装饰器:
http://wiki.python.org/moin/ PythonDecoratorLibrary#Memoize
http://code.activestate.com/recipes/498110-memoize-decorator-with-o1-length-limited-lru-cache/
http://code.activestate.com/ Recipes/496879-memoize-decorator-function-with-cache-size-limit/
提出一个完全通用的解决方案比您想象的要困难。例如,您需要注意不可散列的函数参数,并且需要确保缓存不会变得太大。
如果您确实正在寻找惰性函数调用(仅在需要值时才实际评估函数的调用),您可能可以使用生成器。
编辑:所以我想你真正想要的是惰性评估。这可能就是您正在寻找的库:
http://pypi.python.org/pypi /lazypy/0.5
There are quite a few decorators out there for memoization:
http://wiki.python.org/moin/PythonDecoratorLibrary#Memoize
http://code.activestate.com/recipes/498110-memoize-decorator-with-o1-length-limited-lru-cache/
http://code.activestate.com/recipes/496879-memoize-decorator-function-with-cache-size-limit/
Coming up with a completely general solution is harder than you might think. For instance, you need to watch out for non-hashable function arguments and you need to make sure the cache doesn't grow too large.
If you're really looking for a lazy function call (one where the function is only actually evaluated if and when the value is needed), you could probably use generators for that.
EDIT: So I guess what you want really is lazy evaluation after all. Here's a library that's probably what you're looking for:
http://pypi.python.org/pypi/lazypy/0.5
这里是一个非常简短的惰性装饰器,尽管它缺少使用
@functools.wraps
(实际上返回一个Lazy
实例以及其他一些潜在的陷阱):Here's a pretty brief lazy-decorator, though it lacks using
@functools.wraps
(and actually returns an instance ofLazy
plus some other potential pitfalls):即使经过您的编辑和一系列详细的评论,我仍然不太明白。在第一句话中,您说对 f() 的第一次调用应该调用 g(),但随后返回缓存的值。但随后在您的评论中,您说“无论如何,g() 都不会被调用”(强调我的)。我不确定你在否定什么:你是说 g() 不应该被调用(没有多大意义;为什么 g() 存在?);或者 g()可能被调用,但也可能不会(好吧,这仍然与第一次调用 f() 时调用 g() 相矛盾)。然后,您给出一个根本不涉及 g() 的片段,并且实际上与您的问题的第一句话或与 detly 的评论线程无关。
如果您再次编辑它,这是我回复的片段:
如果这确实是您的问题,那么答案很简单,
那就是如何实现“仅在使用该值时才调用 f(Z)”。
我不完全理解“Z 有点大而无法缓存”。如果您的意思是在程序执行过程中会有太多不同的 Z 值而记忆是无用的,那么也许您必须诉诸于预先计算 f(Z) 的所有值并在运行时查找它们。如果你不能做到这一点(因为你无法知道你的程序将遇到的 Z 值),那么你又回到了记忆。如果这仍然太慢,那么您唯一真正的选择是使用比 Python 更快的东西(尝试 Psyco、Cython、ShedSkin 或手动编码的 C 模块)。
Even after your edit, and the series of comments with detly, I still don't really understand. In your first sentence, you say the first call to f() is supposed to call g(), but subsequently return cached values. But then in your comments, you say "g() doesn't get called no matter what" (emphasis mine). I'm not sure what you're negating: Are you saying g() should never be called (doesn't make much sense; why does g() exist?); or that g() might be called, but might not (well, that still contradicts that g() is called on the first call to f()). You then give a snippet that doesn't involve g() at all, and really doesn't relate to either the first sentence of your question, or to the comment thread with detly.
In case you go editing it again, here is the snippet I am responding to:
If that is really your question, then the answer is simply
That is how to achieve "f(Z) is only called if the value is used".
I don't fully understand "Z is a bit big to cache". If you mean there will be too many different values of Z over the course of program execution that memoization is useless, then maybe you have to resort to precalculating all the values of f(Z) and just looking them up at run time. If you can't do this (because you can't know the values of Z that your program will encounter) then you are back to memoization. If that's still too slow, then your only real option is to use something faster than Python (try Psyco, Cython, ShedSkin, or hand-coded C module).
为了完整起见,这里是我的惰性评估器装饰器食谱的链接:
https:/ /bitbucket.org/jsbueno/metapython/src/f48d6bd388fd/lazy_decorator.py
Just for completness, here is a link for my lazy-evaluator decorator recipe:
https://bitbucket.org/jsbueno/metapython/src/f48d6bd388fd/lazy_decorator.py