Using arguments in a decorator
Steven D'Aprano
steve+comp.lang.python at pearwood.info
Sat Apr 21 04:36:43 EDT 2012
On Fri, 20 Apr 2012 16:57:06 +0100, Rotwang wrote:
> def memo(func):
> def memofunc(*args, **kwargs):
> twargs = tuple(kwargs.items())
> if (args, twargs) in memofunc.d:
> return copy(memofunc.d[(args, twargs)])
> memofunc.d[(args, twargs)] = func(*args, **kwargs) return
> copy(memofunc.d[(args, twargs)])
> memofunc.__name__ = func.__name__
> memofunc.d = {}
> return memofunc
Note that this decorator is underpowered and arguable buggy: it
suppresses the decorated function's doc string. You should use
functools.wraps to copy the name, doc string and anything else necessary.
Here is how I would write the above.
import functools
def memoise(func):
"""Decorator to memoise a function."""
cache = {}
@functools.wraps(func)
def inner(*args, **kwargs):
# Make sure keyword args are always looked up in a consistent
# order by sorting. One minor subtlety: since kwargs cannot
# have duplicate keys, sorted() will never try to break ties
# by comparing values. So this will work even for unsortable
# values like complex numbers.
kw = tuple(sorted(kwargs.items()))
try:
# Cache hit?
result = cache[(args, kw)]
except KeyError:
# Cache miss.
result = func(*args, **kwargs)
cache[(args, kw)] = result
except TypeError:
# Cache failure; at least one argument is uncacheable.
result = func(*args, **kwargs)
# Is the cache too big?
if len(cache) > 1000:
# Dump an arbitrary item. A LRU (least recently used) cache
# would be better, but this will do.
cache.popitem()
return result
# Expose the cache to the outside world.
inner._cache = cache
return inner
[...]
> But I don't know how. I know that I can see the default arguments of the
> original function using func.__defaults__, but without knowing the
> number and names of func's positional arguments (which I don't know how
> to find out) this doesn't help me. Any suggestions?
http://docs.python.org/release/3.1.5/library/inspect.html?#inspect.getfullargspec
>>> def f(a, b=1, *args, c, d=2, **kwargs):
... x = 42
... return (a,b,c,d,args,kwargs)
...
>>> import inspect
>>> inspect.getfullargspec(f)
FullArgSpec(args=['a', 'b'], varargs='args', varkw='kwargs',
defaults=(1,), kwonlyargs=['c', 'd'], kwonlydefaults={'d': 2},
annotations={})
--
Steven
More information about the Python-list
mailing list