inspect feature

8 views
Skip to first unread message

Aaron "Castironpi" Brady

unread,
Oct 8, 2008, 11:35:00 PM10/8/08
to
Hello,

The 'inspect' module has this method:

inspect.getargvalues(frame)

It takes a frame and returns the parameters used to call it, including
the locals as defined in the frame, as shown.

>>> def f( a, b, d= None, *c, **e ):
... import inspect
... return inspect.getargvalues( inspect.currentframe() )
...
>>> f( 0, 1, 'abc', 'def', ( 3, 2 ), h= 'ghi' )
(['a', 'b', 'd'], 'c', 'e', {'a': 0, 'c': ('def', (3, 2)), 'b': 1,
'e': {'h': 'g
hi'}, 'd': 'abc', 'inspect': <module 'inspect' from 'C:\Programs
\Python26\lib\in
spect.pyc'>})

However, if you wanted a decorator that examines the parameters to a
function, you're out of luck. By the time you have a frame, you're
already in the function.

Perhaps it would not be as common as something like 'join' for
example, or even the rest of the functions in 'inspect', but do you
think something similar to 'getargvalues' that accepted a function and
an argument list, and returned a dictionary mapping parameters to
values, could be useful?

Bruno Desthuilliers

unread,
Oct 9, 2008, 4:48:22 AM10/9/08
to
Aaron "Castironpi" Brady a écrit :

> Hello,
>
> The 'inspect' module has this method:
>
> inspect.getargvalues(frame)
>
> It takes a frame and returns the parameters used to call it, including
> the locals as defined in the frame, as shown.
>
>>>> def f( a, b, d= None, *c, **e ):
> ... import inspect
> ... return inspect.getargvalues( inspect.currentframe() )
> ...
>>>> f( 0, 1, 'abc', 'def', ( 3, 2 ), h= 'ghi' )
> (['a', 'b', 'd'], 'c', 'e', {'a': 0, 'c': ('def', (3, 2)), 'b': 1,
> 'e': {'h': 'g
> hi'}, 'd': 'abc', 'inspect': <module 'inspect' from 'C:\Programs
> \Python26\lib\in
> spect.pyc'>})
>
> However, if you wanted a decorator that examines the parameters to a
> function, you're out of luck. By the time you have a frame, you're
> already in the function.

Hem...

def decorator(func):
def _decorator(*args, *kw):
print "func args are ", *args, **kw
return func(*args, **kw)
return _decorator


Aaron "Castironpi" Brady

unread,
Oct 9, 2008, 2:50:41 PM10/9/08
to
On Oct 9, 3:48 am, Bruno Desthuilliers <bruno.

It is less of a problem without tuple unpacking, but you still have
code like:

if len( args )>= 2:
b= args[ 1 ]
else:
try:
b= (somehow check b's default val.)
except NoDefaultVal:
raise ArgumentError

Worse yet, you have it for each parameter. Unless I missed something,
this is the only way to mimic/recreate the signature of the decoratee.

Bruno Desthuilliers

unread,
Oct 10, 2008, 4:36:35 AM10/10/08
to

I don't get what you're after ??? The decorator has full access to both
the actual params *and* the function's signature (via
inspect.getargspec). So your initial question "if you wanted a decorator
that examines the parameters to a function" seems fully answered. You
will indeed have to write a couple lines of code if you want the same
formating as the one you'd get with inspect.currentframe(), but what ?

FWIW, Michele Simionato's decorator module has some trick to allow for
signature-preserving decorators, so you may want to have a look - but
I'm not sure if this would solve your problem - at least in a sane way.

Aaron "Castironpi" Brady

unread,
Oct 10, 2008, 1:18:53 PM10/10/08
to
On Oct 10, 3:36 am, Bruno Desthuilliers <bruno.

It's not exactly the next Millennium problem, but there are some
substantial checks you have to do on a per-parameter basis to see the
same thing that a function sees, when all you have is *args, **kwargs.

You are wrapping a function with this signature:

def f( a, b, c= None, *d, **e ):

You want to find out the values of 'a', 'b', and 'c' in a decorator.
You have these calls:

f( 0, 1, 'abc', 'def', h= 'ghi' )
f( 0, 1 )
f( 0, 1, h= 'abc' )
f( 0, 1, 'abc', c= 'def' ) #raise TypeError: multiple values

How do you determine 'a', 'b', and 'c'?

Gabriel Genellina

unread,
Oct 14, 2008, 3:06:51 AM10/14/08
to pytho...@python.org
En Fri, 10 Oct 2008 14:18:53 -0300, Aaron "Castironpi" Brady
<casti...@gmail.com> escribió:

I'm afraid you'll have to duplicate the logic described here:
http://docs.python.org/reference/expressions.html#id9
To my knowledge, there is no available Python code (in the stdlib or
something) that already does that.

--
Gabriel Genellina

George Sakkis

unread,
Oct 14, 2008, 10:42:24 AM10/14/08
to
On Oct 14, 3:06 am, "Gabriel Genellina" <gagsl-...@yahoo.com.ar>
wrote:

> En Fri, 10 Oct 2008 14:18:53 -0300, Aaron "Castironpi" Brady
> <castiro...@gmail.com> escribió:

I wrote such a beast some time ago; it's hairy but to the best of my
knowledge it seems to reproduce the standard Python logic:
http://code.activestate.com/recipes/551779/

George

Aaron "Castironpi" Brady

unread,
Oct 14, 2008, 2:35:26 PM10/14/08
to

I didn't see a 'got a duplicate argument for keyword "d"' error, but I
can add one if I need to.

Is there some reason why the built-in behavior should not be made
available, such as it's poorly defined outside the function? Or is it
just the fact that it's complicated that keeps it out of 'inspect'?

George Sakkis

unread,
Oct 14, 2008, 3:32:53 PM10/14/08
to
On Oct 14, 2:35 pm, "Aaron \"Castironpi\" Brady"

Why don't you try it out:

>>> def f( a, b, c= None, *d, **e ): pass
>>> getcallargs(f, 0, 1, 'abc', c= 'def' )
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "getcallargs.py", line 53, in getcallargs
"argument '%s'" % (f_name,arg))
TypeError: f() got multiple values for keyword argument 'c'

George

Aaron "Castironpi" Brady

unread,
Oct 14, 2008, 5:00:24 PM10/14/08
to
On Oct 14, 2:32 pm, George Sakkis <george.sak...@gmail.com> wrote:
> On Oct 14, 2:35 pm, "Aaron \"Castironpi\" Brady"
>
>
>
> <castiro...@gmail.com> wrote:
> > On Oct 14, 9:42 am, George Sakkis <george.sak...@gmail.com> wrote:
>
> > > On Oct 14, 3:06 am, "Gabriel Genellina" <gagsl-...@yahoo.com.ar>
> > > wrote:
>
> > > > En Fri, 10 Oct 2008 14:18:53 -0300, Aaron "Castironpi" Brady
> > > > <castiro...@gmail.com> escribió:
>
snip

Excellent.

Here's some more info.

Ver 2.5:

>>> f( c= 0, c= 0 )


Traceback (most recent call last):
File "<stdin>", line 1, in <module>

TypeError: f() got multiple values for keyword argument 'c'

>>> getcallargs( f, c= 0, c= 0 )


Traceback (most recent call last):
File "<stdin>", line 1, in <module>

File "<stdin>", line 64, in getcallargs
TypeError: f() takes at least 2 non-keyword arguments (0 given)

Just the wrong order to check errors in. Note the spacing '..keyword
arguments..'. Not a problem on 2.6:

Ver 2.6:

>>> f( c= 0, c= 0 )
File "<stdin>", line 1
SyntaxError: keyword argument repeated
>>> getcallargs( f, c= 0, c= 0 )
File "<stdin>", line 1
SyntaxError: keyword argument repeated

+1 standard library.

George Sakkis

unread,
Oct 14, 2008, 5:16:45 PM10/14/08
to
On Oct 14, 5:00 pm, "Aaron \"Castironpi\" Brady"

The problem is getcallargs doesn't even see the double entry; if you
print (args, kwds) from within getcallargs you get ((), {'c': 0}). The
SyntaxError raised in 2.6 is more reasonable.

George

Aaron "Castironpi" Brady

unread,
Oct 14, 2008, 9:03:35 PM10/14/08
to
On Oct 14, 4:16 pm, George Sakkis <george.sak...@gmail.com> wrote:
> On Oct 14, 5:00 pm, "Aaron \"Castironpi\" Brady"
>
>
>
> <castiro...@gmail.com> wrote:
(snip

> > Here's some more info.
>
> > Ver 2.5:
>
> > >>> f( c= 0, c= 0 )
>
> > Traceback (most recent call last):
> >   File "<stdin>", line 1, in <module>
> > TypeError: f() got multiple values for keyword argument 'c'>>> getcallargs( f, c= 0, c= 0 )
>
> > Traceback (most recent call last):
> >   File "<stdin>", line 1, in <module>
> >   File "<stdin>", line 64, in getcallargs
> > TypeError: f() takes at least 2 non-keyword  arguments (0 given)
>
> > Just the wrong order to check errors in.
>
> The problem is getcallargs doesn't even see the double entry; if you
> print (args, kwds) from within getcallargs you get ((), {'c': 0}). The
> SyntaxError raised in 2.6 is more reasonable.
>
> George

There are some other bugs in inspect that put getcallargs on par with
the module as is, even without repairing it. And it covers a majority
of cases. Perhaps a lower-level C version could circumvent that, or
have access to the right information.

Reply all
Reply to author
Forward
0 new messages