Get actual call signature?

J

Jarek Zgoda

Say, I have a function defined as:

def fun(arg_one, arg_two='x', arg_three=None):
pass

Is there any way to get actual arguments that will be effectively used
when I call this function in various ways, like:

fun(5) => [5, 'x', None]
fun(5, arg_three=['a', 'b']) => [5, 'x', ['a', 'b']]
fun(5, 'something') => [5, 'something', None]

(et caetera, using all possible mixes of positional, keyword and default
arguments)

I'd like to wrap function definition with a decorator that intercepts
not only passed arguments, but also defaults that will be actually used
in execution.

If this sounds not feasible (or is simply impossible), I'll happily
throw this idea and look for another one. ;)
 
C

castironpi

Say, I have a function defined as:

def fun(arg_one, arg_two='x', arg_three=None):
    pass

Is there any way to get actual arguments that will be effectively used
when I call this function in various ways, like:

fun(5) => [5, 'x', None]
fun(5, arg_three=['a', 'b']) => [5, 'x', ['a', 'b']]
fun(5, 'something') => [5, 'something', None]

(et caetera, using all possible mixes of positional, keyword and default
arguments)

I'd like to wrap function definition with a decorator that intercepts
not only passed arguments, but also defaults that will be actually used
in execution.

If this sounds not feasible (or is simply impossible), I'll happily
throw this idea and look for another one. ;)

It evaluates to a substantial problem. The combinations include
things that Python disallows, such as double-spec. of keywords and
spec'n of keys w/out a dictionary arg; as well as double-spec'ing of
inspection. How do you want to access the parameters? What is the
least redundant way? P.S. Does there exist a possible authority who
doesn't want me to post this?

How about an index of value and list/tuple of name?
def fun(arg_one, arg_two='x', arg_three=None):
fun(5) => [5, 'x', None]
get_args( fun, 5 )->
names= [ 'arg_one', 'arg_two', 'arg_three' ]
vals= [ 5, 'x', None ]
fun(5, arg_three=['a', 'b']) => [5, 'x', ['a', 'b']]
get_args( fun, 5, arg_three=['a', 'b'] )
names= [ 'arg_one', 'arg_two', 'arg_three' ]
vals= [ 5, 'x', ['a', 'b'] ]
fun(5, 'something') => [5, 'something', None]
get_args( fun, 5, 'something' )->
names= [ 'arg_one', 'arg_two', 'arg_three' ]
vals= [ 5, 'something', None ]
 
J

Jarek Zgoda

(e-mail address removed) pisze:
Say, I have a function defined as:

def fun(arg_one, arg_two='x', arg_three=None):
pass

Is there any way to get actual arguments that will be effectively used
when I call this function in various ways, like:

fun(5) => [5, 'x', None]
fun(5, arg_three=['a', 'b']) => [5, 'x', ['a', 'b']]
fun(5, 'something') => [5, 'something', None]

(et caetera, using all possible mixes of positional, keyword and default
arguments)

I'd like to wrap function definition with a decorator that intercepts
not only passed arguments, but also defaults that will be actually used
in execution.

If this sounds not feasible (or is simply impossible), I'll happily
throw this idea and look for another one. ;)

It evaluates to a substantial problem. The combinations include
things that Python disallows, such as double-spec. of keywords and
spec'n of keys w/out a dictionary arg; as well as double-spec'ing of
inspection. How do you want to access the parameters? What is the
least redundant way? P.S. Does there exist a possible authority who
doesn't want me to post this?

Well, after some thinking and research I found this much more
complicated than my first thoughts. However, I found that somebody
already wrote some code to solve similar problem and even described what
has to be done: http://wordaligned.org/articles/echo. Too bad for me,
the most interesting part relies on features introduced with Python 2.5,
while I am still on 2.4.
Anyway, basics still works and fortunately I am in control in both
function definitions and calls.
 
G

George Sakkis

Say, I have a function defined as:

def fun(arg_one, arg_two='x', arg_three=None):
pass

Is there any way to get actual arguments that will be effectively used
when I call this function in various ways, like:

fun(5) => [5, 'x', None]
fun(5, arg_three=['a', 'b']) => [5, 'x', ['a', 'b']]
fun(5, 'something') => [5, 'something', None]

(et caetera, using all possible mixes of positional, keyword and default
arguments)

I'd like to wrap function definition with a decorator that intercepts
not only passed arguments, but also defaults that will be actually used
in execution.

If this sounds not feasible (or is simply impossible), I'll happily
throw this idea and look for another one. ;)

I also needed this for a typecheck module I had written some time ago.
It is feasible, but it's rather hairy. I can dig up the code, polish
it and post it as a recipe (or maybe as a patch to the inspect stdlib
module where it belongs).

George
 
T

Terry Reedy

| Say, I have a function defined as:
|
| def fun(arg_one, arg_two='x', arg_three=None):
| pass
|
| Is there any way to get actual arguments that will be effectively used
| when I call this function in various ways, like:
....

| I'd like to wrap function definition with a decorator that intercepts
| not only passed arguments, but also defaults that will be actually used
| in execution.

You essentially have to do the same thing the interpreter does to call a
function, which, as has been noted, is pretty hairy. You just want to
print the args instead of executing the code.
 
G

George Sakkis

Say, I have a function defined as:
def fun(arg_one, arg_two='x', arg_three=None):
pass
Is there any way to get actual arguments that will be effectively used
when I call this function in various ways, like:
fun(5) => [5, 'x', None]
fun(5, arg_three=['a', 'b']) => [5, 'x', ['a', 'b']]
fun(5, 'something') => [5, 'something', None]
(et caetera, using all possible mixes of positional, keyword and default
arguments)
I'd like to wrap function definition with a decorator that intercepts
not only passed arguments, but also defaults that will be actually used
in execution.
If this sounds not feasible (or is simply impossible), I'll happily
throw this idea and look for another one. ;)

I also needed this for a typecheck module I had written some time ago.
It is feasible, but it's rather hairy. I can dig up the code, polish
it and post it as a recipe (or maybe as a patch to the inspect stdlib
module where it belongs).

George

Posted at http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/551779.
For any correction or improvement, please leave a comment.

George
 
H

Hans Georg Krauthäuser

Say, I have a function defined as:

def fun(arg_one, arg_two='x', arg_three=None):
pass

Is there any way to get actual arguments that will be effectively used
when I call this function in various ways, like:

fun(5) => [5, 'x', None]
fun(5, arg_three=['a', 'b']) => [5, 'x', ['a', 'b']]
fun(5, 'something') => [5, 'something', None]

(et caetera, using all possible mixes of positional, keyword and default
arguments)

I'd like to wrap function definition with a decorator that intercepts
not only passed arguments, but also defaults that will be actually used
in execution.

If this sounds not feasible (or is simply impossible), I'll happily
throw this idea and look for another one. ;)

--
Jarek Zgoda
Skype: jzgoda | GTalk: (e-mail address removed) | voice: +48228430101

"We read Knuth so you don't have to." (Tim Peters)

Perhaps like so:

import inspect

class CLS(object):
def fun(self, arg_one, arg_two='x', arg_three=None):
print get_signature(self)

def get_signature(obj):
frame = inspect.currentframe()
outerframes = inspect.getouterframes(frame)
caller = outerframes[1][0]
try:
args, varargs, varkw, loc = inspect.getargvalues(caller)
allargs = args
allargs.pop(0) # self
if not varargs is None:
allargs += varargs
if not varkw is None:
allargs += varkw
sdict={}
for arg in allargs:
sdict[arg]=caller.f_locals[arg]
ccframe = outerframes[2][0]
ccmodule = inspect.getmodule(ccframe)
try:
slines, start = inspect.getsourcelines(ccmodule)
except:
clen = 100
else:
clen = len(slines)
finfo = inspect.getframeinfo(ccframe, clen)
theindex = finfo[4]
lines = finfo[3]
theline = lines[theindex]
cmd = theline
for i in range(theindex-1, 0, -1):
line = lines
try:
compile (cmd.lstrip(), '<string>', 'exec')
except SyntaxError:
cmd = line + cmd
else:
break
finally:
del frame
del outerframes
del caller
del ccframe

return cmd, sdict

if __name__ == '__main__':
c=CLS()
c.fun(5)
c.fun(5, arg_three=['a', 'b'])
c.fun(5, 'something')
c.fun(5,
'something')

a=c.fun

a(4)

Best Regards

Hans Georg
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,995
Messages
2,570,236
Members
46,822
Latest member
israfaceZa

Latest Threads

Top