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

11
在C/C++中,我经常发现在调试时定义宏很有用,比如说ECHO(x),它会打印变量名和它的值(例如ECHO(variable)可能会打印variable 7)。你可以使用'字符串化'操作符#在宏中获取变量名,如此处所述here。那么在Python中有没有实现这个功能的方法呢?
换句话说,我想要一个函数。
def echo(x):
    #magic goes here

如果像这样调用foo=7; echo(foo)(或者foo=7; echo('foo')),会打印出foo 7。我知道如果我将变量和变量名都传递给函数,做到这一点是微不足道的,但是在调试时我经常使用这样的函数,而重复操作总是让我感到烦恼。

3个回答

8

虽然不是真正的解决方案,但可能很方便(无论如何,您在问题中都有echo('foo')):

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

foo = 7
echo(foo=foo)

更新:使用inspect解决echo(foo)问题。

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

将会打印:

baz/(bar+foo)) 11

那第二个解决方案非常聪明。在研究它的工作原理时,我发现了一个重复的问题这里,虽然你的正则表达式比那里给出的类似答案更健壮一些。 - James
非常好的答案,谢谢。您能简要解释一下正则表达式是如何工作的吗? - Ferguzz
@Ferguzz,它搜索echo,然后\s*-0或多个空格,\(-括号,(.+?)\)$-在行末($)之前的所有符号的非贪婪搜索\)(括号)。更多信息请访问http://www.regular-expressions.info/repeat.html。您还可以[调试正则表达式](https://dev59.com/oHVD5IYBdhLWcg3wE3No#143636)。在交互式Python会话中尝试:`re.compile(r'echo\s*\((.+?)\)$', re.DEBUG)`。 - reclosedev

3

3
这是一种需要您输入更多内容才能调用的解决方案。它依赖于内置函数locals
def print_key(dictionary, key):
    print key, '=', dictionary[key]


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

一个具有您提到的语义的echo也是可能的,使用inspect模块。但是,请阅读inspect文档中的警告。这是一个丑陋的非便携式hack(它不适用于Python的所有实现)。请务必仅在调试时使用它。
思路是查看调用函数的locals。inspect模块允许这样做:调用由frame对象表示,这些对象通过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')

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接