Using arguments in a decorator

Rotwang sg552 at hotmail.co.uk
Sat Apr 21 08:46:29 EDT 2012


On 21/04/2012 09:36, Steven D'Aprano wrote:
> [...]
>
> 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

Thanks. Incidentally, would there be any way to look at the value of 
cache if it weren't for the statement inner._cache = cache? For that 
matter, I don't understand why 'cache' isn't in inner.__globals__.


> [...]
>> 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={})

Cool; that's not available for Python 2 but it looks like 
inspect.getargspec() is and does pretty much the same thing. Also 
inspect.getcallargs() does exactly what I need for my decorator. Thanks 
very much for your help.


-- 
Hate music? Then you'll hate this:

http://tinyurl.com/psymix



More information about the Python-list mailing list