Python functools带有类方法的lru_cache释放对象吗?

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (1)
  • 关注 (0)
  • 查看 (72)

我的代码如下:

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()

但是foo,因此foo.big(a BigClass)仍然活着:

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坚持实例?缓存不使用一些散列而不是实际的对象?

提问于
用户回答回答于

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

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

扫码关注云+社区

领取腾讯云代金券