Skip to main content
 首页 » 编程设计

python之如何使用 traceit 在堆栈跟踪中报告函数输入变量

2025年05月04日16fff_TT

我一直在使用以下代码来跟踪我的程序的执行情况:

import sys 
import linecache 
import random 
 
def traceit(frame, event, arg): 
    if event == "line": 
        lineno = frame.f_lineno 
        filename = frame.f_globals["__file__"] 
        if filename == "<stdin>": 
            filename = "traceit.py" 
        if (filename.endswith(".pyc") or 
            filename.endswith(".pyo")): 
            filename = filename[:-1] 
        name = frame.f_globals["__name__"] 
        line = linecache.getline(filename, lineno) 
        print "%s:%s:%s: %s" % (name,  lineno,frame.f_code.co_name , line.rstrip()) 
    return traceit 
 
 
def main(): 
    print "In main" 
    for i in range(5): 
        print i, random.randrange(0, 10) 
    print "Done." 
 
sys.settrace(traceit) 
main() 

使用此代码或类似代码,是否可以报告某些函数参数的值?换句话说,上面的代码告诉我调用了“哪些”函数,我想知道这些函数调用的输入变量的对应值是“什么”。

提前致谢。

请您参考如下方法:

您发布的 traceit 函数可用于在执行每行代码时打印信息。如果您只需要调用某些函数时的函数名称和参数,我建议改用此跟踪装饰器:

import functools 
 
def trace(f): 
    '''This decorator shows how the function was called''' 
    @functools.wraps(f) 
    def wrapper(*arg,**kw):         
        arg_str=','.join(['%r'%a for a in arg]+['%s=%s'%(key,kw[key]) for key in kw]) 
        print "%s(%s)" % (f.__name__, arg_str) 
        return f(*arg, **kw) 
    return wrapper 

您可以按如下方式使用它:

@trace 
def foo(*args,**kws): 
    pass 
 
foo(1) 
# foo(1)        
foo(y=1) 
# foo(y=1) 
foo(1,2,3) 
# foo(1,2,3) 

编辑:这是一个结合使用 trace 和 traceit 的示例: 下面,trace 以两种不同的方式使用。正常的方法是装饰你定义的函数:

@trace 
def foo(i): 
    .... 

但是你也可以像这样“猴子修补”任何函数,无论你是否定义它:

random.randrange=trace(random.randrange) 

举个例子:

import sys 
import linecache 
import random 
import functools 
 
def trace(f): 
    '''This decorator shows how the function was called''' 
    @functools.wraps(f) 
    def wrapper(*arg,**kw):         
        arg_str=','.join(['%r'%a for a in arg]+['%s=%s'%(key,kw[key]) for key in kw]) 
        print "%s(%s)" % (f.__name__, arg_str) 
        return f(*arg, **kw) 
    return wrapper 
 
def traceit(frame, event, arg): 
    if event == "line": 
        lineno = frame.f_lineno 
        filename = frame.f_globals["__file__"] 
        if filename == "<stdin>": 
            filename = "traceit.py" 
        if (filename.endswith(".pyc") or 
            filename.endswith(".pyo")): 
            filename = filename[:-1] 
        name = frame.f_globals["__name__"] 
        line = linecache.getline(filename, lineno) 
        print "%s:%s:%s: %s" % (name,  lineno,frame.f_code.co_name , line.rstrip()) 
    return traceit 
 
random.randrange=trace(random.randrange) 
 
@trace 
def foo(i): 
    print i, random.randrange(0, 10) 
 
def main(): 
    print "In main" 
    for i in range(5): 
        foo(i) 
    print "Done." 
 
sys.settrace(traceit) 
main()