问题
I have a memoization decorator that looks like this:
def memoize(obj):
from functools import wraps
cache = {}
@wraps(obj)
def memoizer(*args, **kwargs):
if args not in cache:
cache[args] = obj(*args, **kwargs)
return cache[args]
return memoizer
However, I'm not sure this function works properly because it seems like to me it recreates cache
as an empty dictionary every time the decorated function is called. When I test it with a simple fibonacci function, it does appear to memoize correctly. So is cache
not recreated every time?
The python wiki has a version that includes this line:
cache = obj.cache = {}
So I am not sure what this does. I guess that python functions are objects so it is creating a new attribute associated with the function and is publically available/usable every time the function is called.
In either version, if I make repeated calls to the function, as in a recursive definition or just through repeated calls, how is the cache treated? Is it associated with the function, does it become a "global" variable, or something else?
回答1:
1) A new cache
is created for each call to memoize()
. But memoize()
is called only once for each decorated function. Thus each decorated function has its own cache
.
2) Concerning cache = obj.cache = {}
:
Functions are also objects in Python. And as you already assumed, obj.cache = {}
will create a new attribute on the wrapped function. The local cache object and the cache attribute on the wrapped function will point at the same dictionary.
This does not man that cache
is a global variable - it's local in the memoize function and it's a attribute on the function.
If you have a decorated function f
you could access f.cache
on a global scope, if that's what you mean with a global variable.
If you call the decorated function repeatedly, it will always access the same cache
specific to the decorated function.
To work around inner functions not beeing "memoized".
def outer():
# do not add the decorator here!
def inner():
return 5
if(not hasattr(outer, "inner")):
# the "@" decorator is only syntactical sugar,
# we can simply call the decorator function to wrap another function
outer.inner = memoize( inner )
outer.inner()
return outer.inner()
outer()
outer()
来源:https://stackoverflow.com/questions/44577679/memoizing-decorator-keeping-stored-values