首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >Python functools带有类方法的lru_cache : release对象

Python functools带有类方法的lru_cache : release对象
EN

Stack Overflow用户
提问于 2015-11-12 21:21:52
回答 4查看 24.5K关注 0票数 60

如何在不泄漏内存的情况下在类中使用functools的lru_cache?在下面的最小示例中,尽管超出了作用域并且没有referrer (除了lru_cache之外),foo实例也不会被释放。

代码语言:javascript
复制
from functools import lru_cache
class BigClass:
    pass
class Foo:
    def __init__(self):
        self.big = BigClass()
    @lru_cache(maxsize=16)
    def cached_method(self, x):
        return x + 5

def fun():
    foo = Foo()
    print(foo.cached_method(10))
    print(foo.cached_method(10)) # use cache
    return 'something'

fun()

但是foofoo.big (a BigClass)仍然活着

代码语言:javascript
复制
import gc; gc.collect()  # collect garbage
len([obj for obj in gc.get_objects() if isinstance(obj, Foo)]) # is 1

这意味着Foo/BigClass实例仍然驻留在内存中。即使删除Foo (del Foo)也不会释放它们。

为什么lru_cache要保留这个实例?缓存不是使用了一些散列而不是实际的对象吗?

在类中使用lru_caches的推荐方式是什么?

我知道有两种变通方法:Use per instance cachesmake the cache ignore object (但这可能会导致错误的结果)

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2015-11-12 21:26:14

这不是最干净的解决方案,但它对程序员来说是完全透明的:

代码语言:javascript
复制
import functools
import weakref

def memoized_method(*lru_args, **lru_kwargs):
    def decorator(func):
        @functools.wraps(func)
        def wrapped_func(self, *args, **kwargs):
            # We're storing the wrapped method inside the instance. If we had
            # a strong reference to self the instance would never die.
            self_weak = weakref.ref(self)
            @functools.wraps(func)
            @functools.lru_cache(*lru_args, **lru_kwargs)
            def cached_method(*args, **kwargs):
                return func(self_weak(), *args, **kwargs)
            setattr(self, func.__name__, cached_method)
            return cached_method(*args, **kwargs)
        return wrapped_func
    return decorator

它采用与lru_cache完全相同的参数,并且工作方式完全相同。但是,它从不将self传递给lru_cache,而是使用每个实例的lru_cache

票数 41
EN

Stack Overflow用户

发布于 2019-05-05 18:00:25

对于这个用例,我将介绍methodtools

用于安装https://pypi.org/project/methodtools/pip install methodtools

然后,您的代码将只需将functools替换为methodtools即可。

代码语言:javascript
复制
from methodtools import lru_cache
class Foo:
    @lru_cache(maxsize=16)
    def cached_method(self, x):
        return x + 5

当然,gc测试也会返回0。

票数 18
EN

Stack Overflow用户

发布于 2019-10-28 22:18:03

Python3.8在functools模块中引入了cached_property装饰器。在测试时,它似乎没有保留实例。

如果你不想更新到Python3.8,你可以使用source code。您只需导入RLock并创建_NOT_FOUND对象。含义:

代码语言:javascript
复制
from threading import RLock

_NOT_FOUND = object()

class cached_property:
    # https://github.com/python/cpython/blob/v3.8.0/Lib/functools.py#L930
    ...
票数 7
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/33672412

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档