在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
。我意识到如果我将变量及其名称都传递给函数,这样做是微不足道的,但是在调试时我会使用这样的函数,重复总是会让我感到恼火。
答案 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')