代码之家  ›  专栏  ›  技术社区  ›  culebrón

从traceback获取最后一个函数的调用参数?

  •  1
  • culebrón  · 技术社区  · 15 年前

    我可以得到在回溯中调用的最后一个函数的参数吗?怎么用?

    我想为标准错误制作一个捕捉器,使代码可读,同时向用户提供详细信息。

    在下面的示例中,我希望get_params返回一个提供给os.chown的参数元组。检查 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 回复  |  直到 12 年前
        1
  •  0
  •   jamessan    15 年前

    使用修饰符来实现所要实现的功能的问题是,异常处理程序得到的框架是 do_your_job() 不是,不是 os.listdir() S os.makedirs() S或 os.chown() 所以你要打印的信息是 DoYouYouJOP() . 为了达到我认为你想要的行为,你必须装饰你调用的所有库函数。

        2
  •  5
  •   Alex Martelli    15 年前

    对于此类检查任务,始终首先考虑模块 inspect 在标准库中。在这里, inspect.getargvalues 给出给定帧的参数值,以及 inspect.getinnerframes 给出了一个回溯对象的感兴趣的帧。

        3
  •  3
  •   Denis Otkidach    15 年前

    下面是这样一个函数的例子和一些您无法回避的问题:

    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() 显示另一种获得所需帧的方法。虽然它简化了一点,但它也做了一些你不需要的额外工作,同时速度相对较慢。( 检查.getinnerframes()。 读取回溯中每个模块的源文件;这对于一个调试调用并不重要,但在其他情况下可能是一个问题)。