Get actual call signature?

Hans Georg Krauthäuser hgk at ieee.org
Wed Mar 19 04:26:32 EDT 2008


On 18 Mrz., 11:40, Jarek Zgoda <jzg... at o2.usun.pl> wrote:
> 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: zg... at jabber.aster.pl | 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[i]
            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



More information about the Python-list mailing list