从追踪中获取最后一个函数的调用参数?

3 投票
3 回答
2354 浏览
提问于 2025-04-15 15:32

我能否获取到在错误追踪中最后一个调用的函数的参数?怎么做呢?

我想做一个捕捉标准错误的工具,这样可以让代码更易读,同时又能给用户提供详细的信息。

在下面的例子中,我希望GET_PARAMS能返回传给os.chown的参数元组。根据Alex Martelli的建议,我查看了inspect模块,但没有找到相关内容。

def catch_errors(fn):
    def decorator(*args, **kwargs):
        try:
            return fn(*args, **kwargs)
        except (IOError, OSError):
            msg = sys.exc_info()[2].tb_frame.f_locals['error_message']
            quit(msg.format(SEQUENCE_OF_PARAMETERS_OF_THE_LAST_FUNCTION_CALLED)\
            + '\nError #{0[0]}: {0[1]}'.format(sys.exc_info()[1].args), 1)
    return decorator

@catch_errors
def do_your_job():
    error_message = 'Can\'t change folder ownership \'{0}\' (uid:{1}, gid:{2})'
    os.chown('/root', 1000, 1000) # note that params aren't named vars.

if __name == '__main__' and os.getenv('USERNAME') != 'root':
    do_your_job()

(感谢Jim Robert提供的装饰器)

3 个回答

3

这里有一个这样的函数示例,以及一些你无法避免的问题:

import sys

def get_params(tb):
    while tb.tb_next:
        tb = tb.tb_next
    frame = tb.tb_frame
    code = frame.f_code
    argcount = code.co_argcount
    if code.co_flags & 4: # *args
        argcount += 1
    if code.co_flags & 8: # **kwargs
        argcount += 1
    names = code.co_varnames[:argcount]
    params = {}
    for name in names:
        params[name] = frame.f_locals.get(name, '<deleted>')
    return params


def f(a, b=2, c=3, *d, **e):
    del c
    c = 4
    e['g'] = 6
    assert False

try:
    f(1, f=5)
except:
    print get_params(sys.exc_info()[2])

输出结果是:

{'a': 1, 'c': 4, 'b': 2, 'e': {'g': 6, 'f': 5}, 'd': ()}

我没有使用 inspect.getinnerframes() 来展示获取所需帧的另一种方法。虽然这样简化了一些,但它也做了一些额外的工作,这对你来说并不是必须的,而且相对较慢(inspect.getinnerframes() 会为回溯中的每个模块读取源文件;对于一次调试调用来说这并不重要,但在其他情况下可能会成为问题)。

5

在进行这样的检查任务时,首先要想到的是标准库中的 inspect 模块。这里, inspect.getargvalues 可以让你获取某个框架中的参数值,而 inspect.getinnerframes 则可以从一个错误追踪对象中获取你感兴趣的框架。

0

你想用装饰器来解决的问题有点复杂,因为异常处理器得到的上下文是来自 do_your_job() 的,而不是 os.listdir()os.makedirs()os.chown() 的。所以你打印出来的信息其实是 do_your_job() 的参数。为了达到你想要的效果,你需要对你调用的所有库函数都使用装饰器。

撰写回答