Using arguments in a decorator
Ian Kelly
ian.g.kelly at gmail.com
Fri Apr 20 20:07:02 EDT 2012
On Fri, Apr 20, 2012 at 9:57 AM, Rotwang <sg552 at hotmail.co.uk> wrote:
> As far as I know, the decorated function will always return the same value
> as the original function. The problem is that the dictionary key stored
> depends on how the function was called, even if two calls should be
> equivalent; hence the original function gets called more often than
> necessary. For example, there's this:
>
>>>> @memo
> def f(x, y = None, *a, **k):
> return x, y, a, k
>
>>>> f(1, 2)
> (1, 2, (), {})
>>>> f.d
> {((1, 2), ()): (1, 2, (), {})}
>>>> f(y = 2, x = 1)
> (1, 2, (), {})
>>>> f.d
> {((1, 2), ()): (1, 2, (), {}), ((), (('y', 2), ('x', 1))): (1, 2, (), {})}
Using the FunctionMaker from the third-party decorator module [1]:
from copy import copy
import inspect
from decorator import FunctionMaker
memo_body = """
key = (%s)
if key not in cache:
cache[key] = func(%%(signature)s)
return copy(cache[key])
"""
def memo(func):
(args, varargs, varkw, defaults) = inspect.getargspec(func)
if varargs:
args.append(varargs)
if varkw:
args.append("tuple(sorted(%s.items()))" % varkw)
cache = {}
decorated = FunctionMaker.create(func, memo_body % ', '.join(args),
dict(func=func, cache=cache, copy=copy))
decorated.d = cache
return decorated
>>> @memo
... def f(x, y=None, *a, **k):
... return x, y, a, k
...
>>> f(1, 2)
(1, 2, (), {})
>>> f.d
{(1, 2, (), ()): (1, 2, (), {})}
>>> f(y=2, x=1)
(1, 2, (), {})
>>> f.d
{(1, 2, (), ()): (1, 2, (), {})}
Cheers,
Ian
[1] http://pypi.python.org/pypi/decorator
More information about the Python-list
mailing list