在某些情况下,我想打印调试样式的输出:
# module test.py
def f()
a = 5
b = 8
debug(a, b) # line 18
我希望debug
函数能够打印以下内容:
debug info at test.py: 18
function f
a = 5
b = 8
我认为应该可以通过使用inspect模块定位堆栈框架,然后查找相应的行,查找该行中的源代码,从那里获取参数的名称。可以通过向上移动一个堆栈帧来获得函数名称。 (参数的值很容易获得:它们直接传递给函数debug
。)
我是否在正确的轨道上?有没有我可以参考的食谱?
答案 0 :(得分:3)
你可以按照以下几点做点什么:
import inspect
def debug(**kwargs):
st = inspect.stack()[1]
print '%s:%d %s()' % (st[1], st[2], st[3])
for k, v in kwargs.items():
print '%s = %s' % (k, v)
def f():
a = 5
b = 8
debug(a=a, b=b) # line 12
f()
打印出来:
test.py:12 f()
a = 5
b = 8
答案 1 :(得分:1)
你通常做得很好,尽管使用AOP来完成这类任务会更容易。基本上,不是每次都使用每个变量调用“debug”,而是可以使用在某些事件上执行某些操作的方面来装饰代码,例如在输入函数以打印传递的变量及其名称时。
答案 2 :(得分:1)
是的,你是在正确的轨道上。您可能希望查看inspect.getargspec,它将返回args,varargs,关键字,传递给函数的默认值的命名元组。
import inspect
def f():
a = 5
b = 8
debug(a, b)
def debug(a, b):
print inspect.getargspec(debug)
f()
答案 3 :(得分:0)
这真的很棘手。让我尝试给出一个更完整的答案重用this code,并在Senthil的答案中提示getargspec
让我以某种方式触发。顺便说一下,{3.0}和getfullarcspec
should be used中不推荐使用getargspec
。
这对我来说在Python 3.1.2上都可以显式调用调试函数并使用装饰器:
# from: https://stackoverflow.com/a/4493322/923794
def getfunc(func=None, uplevel=0):
"""Return tuple of information about a function
Go's up in the call stack to uplevel+1 and returns information
about the function found.
The tuple contains
name of function, function object, it's frame object,
filename and line number"""
from inspect import currentframe, getouterframes, getframeinfo
#for (level, frame) in enumerate(getouterframes(currentframe())):
# print(str(level) + ' frame: ' + str(frame))
caller = getouterframes(currentframe())[1+uplevel]
# caller is tuple of:
# frame object, filename, line number, function
# name, a list of lines of context, and index within the context
func_name = caller[3]
frame = caller[0]
from pprint import pprint
if func:
func_name = func.__name__
else:
func = frame.f_locals.get(func_name, frame.f_globals.get(func_name))
return (func_name, func, frame, caller[1], caller[2])
def debug_prt_func_args(f=None):
"""Print function name and argument with their values"""
from inspect import getargvalues, getfullargspec
(func_name, func, frame, file, line) = getfunc(func=f, uplevel=1)
argspec = getfullargspec(func)
#print(argspec)
argvals = getargvalues(frame)
print("debug info at " + file + ': ' + str(line))
print(func_name + ':' + str(argvals)) ## reformat to pretty print arg values here
return func_name
def df_dbg_prt_func_args(f):
"""Decorator: dpg_prt_func_args - Prints function name and arguments
"""
def wrapped(*args, **kwargs):
debug_prt_func_args(f)
return f(*args, **kwargs)
return wrapped
用法:
@df_dbg_prt_func_args
def leaf_decor(*args, **kwargs):
"""Leaf level, simple function"""
print("in leaf")
def leaf_explicit(*args, **kwargs):
"""Leaf level, simple function"""
debug_prt_func_args()
print("in leaf")
def complex():
"""A complex function"""
print("start complex")
leaf_decor(3,4)
print("middle complex")
leaf_explicit(12,45)
print("end complex")
complex()
并打印:
start complex
debug info at debug.py: 54
leaf_decor:ArgInfo(args=[], varargs='args', keywords='kwargs', locals={'args': (3, 4), 'f': <function leaf_decor at 0x2aaaac048d98>, 'kwargs': {}})
in leaf
middle complex
debug info at debug.py: 67
leaf_explicit:ArgInfo(args=[], varargs='args', keywords='kwargs', locals={'args': (12, 45), 'kwargs': {}})
in leaf
end complex
装饰者作弊:因为在wrapped
中我们获得与函数本身相同的参数,我们在wrapped
中找到并报告getfunc
的ArgSpec并不重要。 debug_prt_func_args
。这段代码可以稍微美化一下,但是对于我使用的简单调试测试用例,它现在可以正常工作。
您可以做的另一个技巧:如果您取消注释for
中的getfunc
- 循环,您可以看到inspect
可以为您提供“上下文”,它实际上是源代码行调用函数的地方。这段代码显然没有显示给你的函数赋予的任何变量的内容,但有时它已经有助于知道在被调用函数之上一级使用的变量名。
如您所见,使用装饰器您不必更改函数内的代码。
可能你会想要打印args。我在函数中留下了原始打印(以及注释掉的打印声明),因此更容易使用。