Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.python > #42723

Re: Decorating functions without losing their signatures

From Rotwang <sg552@hotmail.co.uk>
Newsgroups comp.lang.python
Subject Re: Decorating functions without losing their signatures
Date 2013-04-04 02:44 +0100
Organization A noiseless patient Spider
Message-ID <kjilpp$5s1$1@dont-email.me> (permalink)
References <kjfv4f$4g1$1@dont-email.me>

Show all headers | View raw


On 03/04/2013 02:05, Rotwang wrote:
> [...]
>
> After thinking about it for a while I've come up with the following
> abomination:
>
> import inspect
>
> def sigwrapper(sig):
>    if not isinstance(sig, inspect.Signature):
>      sig = inspect.signature(sig)
>    def wrapper(f):
>      ps = 'args = []\n\t\t'
>      ks = 'kwargs = {}\n\t\t'
>      for p in sig.parameters.values():
>        if p.kind in (p.POSITIONAL_ONLY, p.POSITIONAL_OR_KEYWORD):
>          ps = '%sargs.append(%s)\n\t\t' % (ps, p.name)
>        elif p.kind == p.VAR_POSITIONAL:
>          ps = '%sargs.extend(%s)\n\t\t' % (ps, p.name)
>        elif p.kind == p.KEYWORD_ONLY:
>          ks = '%skwargs[%r] = %s\n\t\t' % (ks, p.name, p.name)
>        elif p.kind == p.VAR_KEYWORD:
>          ks = '%skwargs.update(%s)\n\t\t' % (ks, p.name)
>      loc = {'wrapped': f}
>      defstring = ('def wrapouter(wrapped = wrapped):'
>                   '\n\tdef wrapinner%s:'
>                   '\n\t\t%s%sreturn wrapped(*args, **kwargs)'
>                   '\n\treturn wrapinner' % (sig, ps, ks))
>      exec(defstring, f.__globals__, loc)
>      return loc['wrapouter']()
>    return wrapper

Oops! Earlier I found out the hard way that this fails when the 
decorated function has arguments called 'args' or 'kwargs'. Here's a 
modified version that fixes said bug, but presumably not the many others 
I haven't noticed yet:

def sigwrapper(sig):
   if not isinstance(sig, inspect.Signature):
     sig = inspect.signature(sig)
   n = 0
   while True:
     pn = 'p_%i' % n
     kn = 'k_%i' % n
     if pn not in sig.parameters and kn not in sig.parameters:
       break
     n += 1
   ps = '%s = []\n\t\t' % pn
   ks = '%s = {}\n\t\t' % kn
   for p in sig.parameters.values():
     if p.kind in (p.POSITIONAL_ONLY, p.POSITIONAL_OR_KEYWORD):
       ps = '%s%s.append(%s)\n\t\t' % (ps, pn, p.name)
     elif p.kind == p.VAR_POSITIONAL:
       ps = '%s%s.extend(%s)\n\t\t' % (ps, pn, p.name)
     elif p.kind == p.KEYWORD_ONLY:
       ks = '%s%s[%r] = %s\n\t\t' % (ks, kn, p.name, p.name)
     elif p.kind == p.VAR_KEYWORD:
       ks = '%s%s.update(%s)\n\t\t' % (ks, kn, p.name)
   defstring = ('def wrapouter(wrapped = wrapped):'
                '\n\tdef wrapinner%s:'
                '\n\t\t%s%sreturn wrapped(*%s, **%s)'
                '\n\treturn wrapinner' % (sig, ps, ks, pn, kn))
   def wrapper(f):
     loc = {'wrapped': f}
     exec(defstring, f.__globals__, loc)
     return loc['wrapouter']()
   return wrapper

Back to comp.lang.python | Previous | NextPrevious in thread | Find similar | Unroll thread


Thread

Decorating functions without losing their signatures Rotwang <sg552@hotmail.co.uk> - 2013-04-03 02:05 +0100
  Re: Decorating functions without losing their signatures Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-04-03 04:15 +0000
    Re: Decorating functions without losing their signatures Rotwang <sg552@hotmail.co.uk> - 2013-04-04 02:53 +0100
  Re: Decorating functions without losing their signatures Jan Riechers <janpeterr@freenet.de> - 2013-04-03 08:06 +0300
  Re: Decorating functions without losing their signatures Michele Simionato <michele.simionato@gmail.com> - 2013-04-03 18:18 -0700
    Re: Decorating functions without losing their signatures Rotwang <sg552@hotmail.co.uk> - 2013-04-04 03:17 +0100
  Re: Decorating functions without losing their signatures Rotwang <sg552@hotmail.co.uk> - 2013-04-04 02:44 +0100

csiph-web