How to find the name of a variable that was passed to a function?

前端 未结 3 1430
囚心锁ツ
囚心锁ツ 2020-12-09 06:14

In C/C++, I have often found it useful while debugging to define a macro, say ECHO(x), that prints out the variable name and its value (i.e. ECHO(variable

相关标签:
3条回答
  • 2020-12-09 06:46
    def echo(x):
        import inspect
        print "{0}: {1}".format(x, inspect.stack()[1][0].f_locals[x])
    y = 123
    echo('y')
    # 'y: 123'
    

    See also: https://stackoverflow.com/a/2387854/16361

    Note that this can cause GC issues:

    http://docs.python.org/library/inspect.html#the-interpreter-stack

    It will also turn off people who have been burned by messing with frames, and may leave a bad taste in your mouth. But it will work.

    0 讨论(0)
  • 2020-12-09 06:50

    Here's a solution that has you type a bit more to call it. It relies on the locals built-in function:

    def print_key(dictionary, key):
        print key, '=', dictionary[key]
    
    
    foo = 7
    print_key(locals(), 'foo')
    

    An echo with the semantics you mentioned is also possible, using the inspect module. However, do read the warnings in inspect's documentation. This is an ugly non-portable hack (it doesn't work in all implementations of Python). Be sure to only use it for debugging.

    The idea is to look into the locals of the calling function. The inspect module allows just that: calls are represented by frame objects linked together by the f_back attribute. Each frame's local and global variables are available (there are also builtins, but you're unlikely to need to print them).

    You may want to explicitly delete any references frame objects to prevent reference cycles, as explained in inspect docs, but this is not strictly necessary – the garbage collection will free them sooner or later.

    import inspect
    
    def echo(varname):
        caller = inspect.currentframe().f_back
        try:
            value = caller.f_locals[varname]
        except KeyError:
            value = caller.f_globals[varname]
        print varname, '=', value
        del caller
    
    foo = 7
    echo('foo')
    
    0 讨论(0)
  • 2020-12-09 06:58

    Not really solution, but may be handy (anyway you have echo('foo') in question):

    def echo(**kwargs):
        for name, value in kwargs.items():
            print name, value
    
    foo = 7
    echo(foo=foo)
    

    UPDATE: Solution for echo(foo) with inspect

    import inspect
    import re
    
    def echo(arg):
        frame = inspect.currentframe()
        try:
            context = inspect.getframeinfo(frame.f_back).code_context
            caller_lines = ''.join([line.strip() for line in context])
            m = re.search(r'echo\s*\((.+?)\)$', caller_lines)
            if m:
                caller_lines = m.group(1)
            print caller_lines, arg
        finally:
            del frame
    
    foo = 7
    bar = 3
    baz = 11
    echo(foo)
    echo(foo + bar)
    echo((foo + bar)*baz/(bar+foo))
    

    Output:

    foo 7
    foo + bar 10
    (foo + bar)*baz/(bar+foo) 11
    

    It has the smallest call, but it's sensitive to newlines, e.g.:

    echo((foo + bar)*
          baz/(bar+foo))
    

    Will print:

    baz/(bar+foo)) 11
    
    0 讨论(0)
提交回复
热议问题