是否有一个装饰器可以简单地缓存函数返回值?
考虑以下事项:
@property
def name(self):
if not hasattr(self, '_name'):
# expensive calculation
self._name = 1 + 1
return self._name
我是新手,但我认为缓存可以分解到装饰器中。 只是我没有找到类似的;)
PS 真正的计算并不依赖于可变值
Consider the following:
@property
def name(self):
if not hasattr(self, '_name'):
# expensive calculation
self._name = 1 + 1
return self._name
I'm new, but I think the caching could be factored out into a decorator. Only I didn't find one like it ;)
PS the real calculation doesn't depend on mutable values
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(20)
从Python 3.2开始,有一个内置的装饰器:
@functools .lru_cache(maxsize=100, typed=False)
用于计算 Fibonacci 数 的 LRU 缓存示例:
如果您无法使用 Python 2.x,请参阅以下示例其他兼容的记忆库列表:
functools32
| PyPI | 源代码repoze.lru
| PyPI | 源代码pylru
| PyPI | 源代码backports.functools_lru_cache
| PyPI | 源代码Starting from Python 3.2 there is a built-in decorator:
@functools.lru_cache(maxsize=100, typed=False)
Example of an LRU cache for computing Fibonacci numbers:
If you are stuck with Python 2.x, here's a list of other compatible memoization libraries:
functools32
| PyPI | Source coderepoze.lru
| PyPI | Source codepylru
| PyPI | Source codebackports.functools_lru_cache
| PyPI | Source codePython 3.8
functools.cached_property
装饰器https://docs.python.org/dev/library/functools.html#functools.cached_property
来自 Werkzeug 的
cached_property
被提到:https://stackoverflow.com/a/5295190/895245 但据说派生版本将合并到 3.8 中,这非常棒。该装饰器可以被视为缓存
@property
,或者当您没有任何参数时作为更干净的@functools.lru_cache
。文档说:
Python 3.8
functools.cached_property
decoratorhttps://docs.python.org/dev/library/functools.html#functools.cached_property
cached_property
from Werkzeug was mentioned at: https://stackoverflow.com/a/5295190/895245 but a supposedly derived version will be merged into 3.8, which is awesome.This decorator can be seen as caching
@property
, or as a cleaner@functools.lru_cache
for when you don't have any arguments.The docs say:
functools.cache
已在 Python 3.9 中发布 (docs):在以前的 Python 版本中,早期答案之一仍然是有效的解决方案:使用
lru_cache
作为普通缓存,没有限制和lru功能。 (文档)这是它的一个更漂亮的版本:
functools.cache
has been released in Python 3.9 (docs):In previous Python versions, one of the early answers is still a valid solution: Using
lru_cache
as an ordinary cache without the limit and lru features. (docs)Here is a prettier version of it:
听起来您不要求通用的记忆化装饰器(即,您对想要缓存不同参数值的返回值的一般情况不感兴趣)。 也就是说,你想要这样:
而通用的记忆装饰器会给你这个:
我认为方法调用语法是更好的风格,因为它表明了昂贵的计算的可能性,而属性语法表明了快速的计算抬头。
[更新:我之前链接到并引用的基于类的记忆装饰器不适用于方法。 我已将其替换为装饰器函数。] 如果您愿意使用通用的记忆化装饰器,这里有一个简单的:
示例用法:
可以找到另一个对缓存大小有限制的记忆化装饰器 此处。
It sounds like you're not asking for a general-purpose memoization decorator (i.e., you're not interested in the general case where you want to cache return values for different argument values). That is, you'd like to have this:
while a general-purpose memoization decorator would give you this:
I submit that the method-call syntax is better style, because it suggests the possibility of expensive computation while the property syntax suggests a quick lookup.
[Update: The class-based memoization decorator I had linked to and quoted here previously doesn't work for methods. I've replaced it with a decorator function.] If you're willing to use a general-purpose memoization decorator, here's a simple one:
Example usage:
Another memoization decorator with a limit on the cache size can be found here.
样品用途:
Sample uses:
Werkzeug 有一个
cached_property
装饰器(docs ,来源)Werkzeug has a
cached_property
decorator (docs, source)我编写了这个简单的装饰器类来缓存函数响应。 我发现它对我的项目非常有用:
用法很简单:
I coded this simple decorator class to cache function responses. I find it VERY useful for my projects:
The usage is straightforward:
尝试joblib
https://joblib.readthedocs.io/en/latest/memory.html
Try joblib
https://joblib.readthedocs.io/en/latest/memory.html
免责声明:我是kids.cache的作者。
您应该检查
kids.cache
,它提供了一个适用于 python 2 和 python 3 的@cache
装饰器。没有依赖项,大约 100 行代码。 使用起来非常简单,例如,考虑到您的代码,您可以像这样使用它:然后
或者您可以将
@cache
装饰器放在@property
(相同的结果)。在属性上使用缓存称为延迟评估,kids.cache 可以做更多事情(它适用于具有任何参数、属性、任何类型的方法,甚至类的函数) ...)。 对于高级用户,
kids.cache
支持cachetools
,它为 python 2 和 python 3 提供了精美的缓存存储(LRU、LFU、TTL、RR 缓存)。重要说明:
kids.cache
的默认缓存存储是一个标准字典,不建议用于具有不同查询的长时间运行的程序,因为它会导致不断增长的数据缓存存储。 对于这种用法,您可以插入其他缓存存储,例如使用 (@cache(use=cachetools.LRUCache(maxsize=2))
来装饰您的函数/属性/类/方法...)DISCLAIMER: I'm the author of kids.cache.
You should check
kids.cache
, it provides a@cache
decorator that works on python 2 and python 3. No dependencies, ~100 lines of code. It's very straightforward to use, for instance, with your code in mind, you could use it like this:Then
Or you could put the
@cache
decorator after the@property
(same result).Using cache on a property is called lazy evaluation,
kids.cache
can do much more (it works on function with any arguments, properties, any type of methods, and even classes...). For advanced users,kids.cache
supportscachetools
which provides fancy cache stores to python 2 and python 3 (LRU, LFU, TTL, RR cache).IMPORTANT NOTE: the default cache store of
kids.cache
is a standard dict, which is not recommended for long running program with ever different queries as it would lead to an ever growing caching store. For this usage you can plugin other cache stores using for instance (@cache(use=cachetools.LRUCache(maxsize=2))
to decorate your function/property/class/method...)啊,只需要为此找到正确的名称:“延迟属性评估”。
我也经常这样做; 也许有一天我会在我的代码中使用这个食谱。
Ah, just needed to find the right name for this: "Lazy property evaluation".
I do this a lot too; maybe I'll use that recipe in my code sometime.
Python Wiki 上还有另一个 memoize 装饰器示例:
http:// /wiki.python.org/moin/PythonDecoratorLibrary#Memoize
这个例子有点聪明,因为如果参数是可变的,它不会缓存结果。 (检查该代码,它非常简单且有趣!)
There is yet another example of a memoize decorator at Python Wiki:
http://wiki.python.org/moin/PythonDecoratorLibrary#Memoize
That example is a bit smart, because it won't cache the results if the parameters are mutable. (check that code, it's very simple and interesting!)
如果您使用 Django 框架,它具有这样的属性来缓存 API 的视图或响应
使用
@cache_page(time)
并且还可以有其他选项。示例:
更多详细信息可以在此处找到。
If you are using Django Framework, it has such a property to cache a view or response of API's
using
@cache_page(time)
and there can be other options as well.Example:
More details can be found here.
有 fastcache,它是“Python 3 functools.lru_cache 的 C 实现。提供 10- 的加速比标准库高 30 倍。”
与选择的答案相同,只是导入不同:
此外,它安装在Anaconda,与 functools 不同,需要已安装。
There is fastcache, which is "C implementation of Python 3 functools.lru_cache. Provides speedup of 10-30x over standard library."
Same as chosen answer, just different import:
Also, it comes installed in Anaconda, unlike functools which needs to be installed.
连同 Memoize 示例 我发现了以下 python 包:
Along with the Memoize Example I found the following python packages:
默认属性不好
@lru_cache
对于我的@mem
装饰器的:输出:
@lru_cache
is not good with default attrsmy
@mem
decorator:output:
创建您自己的装饰器并
在函数端使用它
Create your own decorator and use it
Now at the function side
我实现了类似的东西,使用 pickle 来实现持久性,并使用 sha1 来实现几乎肯定唯一的短 ID。 基本上,缓存对函数代码和参数历史进行哈希处理以获取 sha1,然后查找名称中包含该 sha1 的文件。 如果存在,则打开它并返回结果; 如果不是,则调用该函数并保存结果(可选地,仅在需要一定时间处理时才保存)。
也就是说,我发誓我发现了一个现有的模块可以做到这一点,并且发现自己在这里试图找到该模块...我能找到的最接近的是这个,它看起来差不多是正确的: http://chase-seibert.github.io/blog/2011/11 /23/pythondjango-disk-based-caching-decorator.html
我看到的唯一问题是它不适用于大型输入,因为它对 str(arg) 进行哈希处理,这对于巨型输入来说并不是唯一的数组。
如果有一个 unique_hash() 协议让一个类返回其内容的安全哈希值,那就太好了。 我基本上是为我关心的类型手动实现的。
I implemented something like this, using pickle for persistance and using sha1 for short almost-certainly-unique IDs. Basically the cache hashed the code of the function and the hist of arguments to get a sha1 then looked for a file with that sha1 in the name. If it existed, it opened it and returned the result; if not, it calls the function and saves the result (optionally only saving if it took a certain amount of time to process).
That said, I'd swear I found an existing module that did this and find myself here trying to find that module... The closest I can find is this, which looks about right: http://chase-seibert.github.io/blog/2011/11/23/pythondjango-disk-based-caching-decorator.html
The only problem I see with that is it wouldn't work well for large inputs since it hashes str(arg), which isn't unique for giant arrays.
It would be nice if there were a unique_hash() protocol that had a class return a secure hash of its contents. I basically manually implemented that for the types I cared about.
如果您使用的是 Django 并且想要缓存视图,请参阅 Nikhil Kumar 的回答。
但是如果你想缓存任何函数结果,你可以使用 django-cache-utils< /a>.
它重用 Django 缓存并提供易于使用的
cached
装饰器:If you are using Django and want to cache views, see Nikhil Kumar's answer.
But if you want to cache ANY function results, you can use django-cache-utils.
It reuses Django caches and provides easy to use
cached
decorator:函数缓存简单解决方案
使用 ttl(生存时间)和 max_entries 的
使用示例
复制装饰器代码
Function cache simple solution
with ttl (time to life) and max_entries
Example use
Copy the decorator code
使用示例
Example use