任何人都可以帮助我了解即使在 _cachedf 函数返回后缓存变量仍然存在吗?
它与 Python 的引用计数垃圾收集器有关。该cache
变量将被保存且可访问,因为函数_cachedf
具有对它的引用,并且调用者cached
具有对它的引用。当您再次调用该函数时,您仍在使用最初创建的同一函数对象,因此您仍然可以访问缓存。
在所有对它的引用都被销毁之前,您不会丢失缓存。您可以使用del
运算符来执行此操作。
例如:
>>> import time
>>> def cached(f):
... cache = {} # <---- not an attribute this time!
... def _cachedf(*args):
... if args not in cache:
... cache[args] = f(*args)
... return cache[args]
... return _cachedf
...
...
>>> def foo(duration):
... time.sleep(duration)
... return True
...
...
>>> bob = cached(foo)
>>> bob(2) # Takes two seconds
True
>>> bob(2) # returns instantly
True
>>> del bob # Deletes reference to bob (aka _cachedf) which holds ref to cache
>>> bob = cached(foo)
>>> bob(2) # takes two seconds
True
>>>
作为记录,您想要实现的称为Memoization,装饰器模式页面提供了一个更完整的记忆装饰器,它做同样的事情,但使用了一个装饰器类。您的代码和基于类的装饰器本质上是相同的,基于类的装饰器在存储之前会检查哈希能力。
编辑(2017-02-02):@SiminJie 评论cached(foo)(2)
总是会导致延迟。
这是因为cached(foo)
返回一个带有新缓存的新函数。调用时cached(foo)(2)
,会创建一个新的(空)缓存,然后立即调用缓存的函数。
由于缓存为空且找不到值,因此它重新运行底层函数。相反,做cached_foo = cached(foo)
然后cached_foo(2)
多次调用。这只会导致第一次通话的延迟。此外,如果用作装饰器,它将按预期工作:
@cached
def my_long_function(arg1, arg2):
return long_operation(arg1,arg2)
my_long_function(1,2) # incurs delay
my_long_function(1,2) # doesn't
如果您不熟悉装饰器,请查看此答案以了解上述代码的含义。