如何找到传递给函数的变量的名称?

时间:2012-01-13 19:17:33

标签: python variables reflection

在C / C ++中,我经常发现它在调试时有用,可以定义一个宏,比如ECHO(x),它打印出变量名称及其值(即ECHO(variable)可能会打印variable 7 })。您可以使用'{stringification'运算符#在宏中获取变量名称,如here所述。有没有办法在Python中执行此操作?

换句话说,我想要一个功能

def echo(x):
    #magic goes here

如果被称为foo=7; echo(foo)(或foo=7; echo('foo'),则可能会打印出foo 7。我意识到如果我将变量及其名称都传递给函数,这样做是微不足道的,但是在调试时我会使用这样的函数,重复总是会让我感到恼火。

3 个答案:

答案 0 :(得分:7)

不是真的解决方案,但可能很方便(无论如何你有问题echo('foo')):

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

foo = 7
echo(foo=foo)

更新: echo(foo) <{1}}的解决方案

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))

它具有最小的调用,但它对换行符很敏感,例如:

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

将打印:

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

答案 1 :(得分:3)

def echo(x):
    import inspect
    print "{0}: {1}".format(x, inspect.stack()[1][0].f_locals[x])
y = 123
echo('y')
# 'y: 123'

另请参阅:https://stackoverflow.com/a/2387854/16361

请注意,这可能会导致GC问题:

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

它还会关闭因弄乱框架而被烧伤的人,并且可能会在嘴里留下不好的味道。但它会奏效。

答案 2 :(得分:3)

这是一个解决方案,你可以输入更多信息来调用它。它依赖于locals内置函数:

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


foo = 7
print_key(locals(), 'foo')

使用inspect模块,也可以使用您提到的语义echo。但是,请阅读inspect的文档中的警告。这是一个丑陋的非可移植黑客(它不适用于Python的所有实现)。请务必仅将其用于调试。

想法是调查调用函数的locals。 inspect模块允许:调用由f_back属性链接在一起的帧对象表示。每个框架的局部变量和全局变量都可用(也有内置变量,但您不太可能需要打印它们。)

您可能希望显式删除任何引用框架对象以防止引用周期,如inspect docs中所述,但这不是绝对必要的 - 垃圾收集迟早会释放它们。

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')