【问题标题】:Get last function's call arguments from traceback?从回溯中获取最后一个函数的调用参数?
【发布时间】:2009-10-30 16:02:46
【问题描述】:

我可以获取回溯中调用的最后一个函数的参数吗?怎么样?

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

在以下示例中,我希望 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装饰者)

【问题讨论】:

  • 你的 except 应该是“except (IOError, OSError):”。目前,您只是捕获 IOError,然后将异常实例分配给 OSError。

标签: python exception-handling traceback


【解决方案1】:

对于此类检查任务,请始终首先考虑标准库中的模块inspect。在这里,inspect.getargvalues 为您提供给定帧的参数值,inspect.getinnerframes 为您提供来自回溯对象的感兴趣的帧。

【讨论】:

    【解决方案2】:

    以下是此类功能的示例以及您无法解决的一些问题:

    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() 读取回溯中每个模块的源文件;这对于一个调试调用并不重要,但可能是一个问题其他情况)。

    【讨论】:

    • 我不明白:什么是慢 - 检查还是你的方式?
    • 似乎您的代码只有在函数内部引发异常时才有效。
    【解决方案3】:

    使用装饰器实现的问题在于异常处理程序获取的帧是do_your_job()s,而不是os.listdir()s、os.makedirs()s 或os.chown()s。所以你要打印的信息是do_your_job() 的参数。为了获得我认为您想要的行为,您必须装饰您正在调用的所有库函数。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-05-10
      • 2017-01-28
      • 2011-11-04
      • 2018-05-10
      • 2015-12-06
      • 1970-01-01
      相关资源
      最近更新 更多