【问题标题】:Exceptions: How to display which function caused the exception?异常:如何显示哪个函数导致了异常?
【发布时间】:2022-01-04 21:59:04
【问题描述】:

我有一个看起来像这样的代码块:

try:
    if x == 1:
        a()
    if x == 2:
        b()
    if x == 3:
        c()
except Exception:
    raise Exception("Problem in function")

每个函数a()b()c()都可以有异常。无论如何我可以通过一条消息引发异常,告诉哪个函数导致了异常。

我想知道它是否可以在这里不单独在每个函数中使用trycatch 语句。

【问题讨论】:

  • 你为什么要捕获原始异常?
  • 用x的值找出来?让原始错误消失而不是抓住它并抛出一个新错误? 旧错误引发新错误?
  • (即使捕获原始异常是正确的,也有办法做到这一点 - 事实上,Python 应该已经为你做到了,尽管手动有更好的方法- 但很可能您根本不应该捕获原始异常。)

标签: python exception


【解决方案1】:

我首先想到的是尝试这样的事情:

try:
    if x == 1:
        a()
    if x == 2:
        b()
    if x == 3:
        c()
except Exception:
    raise Exception("Problem in function, x=%s"%x)

现在,当引发异常时,您可以看到 x 的值是什么。

更详细的,可能是这样的:

try:
    if x == 1:
        flabel = 'func_a'
        a()
    if x == 2:
        flabel = 'func_b'
        b()
    if x == 3:
        flable = 'func_c'
        c()
except Exception:
    raise Exception("Problem in function %s"%flabel)

【讨论】:

    【解决方案2】:

    这可能对您的示例过于具体,但我通常会尝试重构代码并具体说明将要执行的函数。

    if x == 1:
        func_name = "a"
        func = a
    elif x == 2:
        func_name = "b"
        func = b
    elif x == 3:
        func_name = "c"
        func = c
    
    try:
        func()
    except Exception:
        raise Exception(f"Problem in {func_name}")
    

    您可以去掉func_name 并改用func.__name__,只要所有三个函数都由它们的“原始”名称引用。

    【讨论】:

    • 你能给我一个如何使用func的例子吗。_ name _.
    • 您实际上只是使用它而不是func_namef'Problem in {func.__name__}'.
    【解决方案3】:

    你可以试试

    import traceback
    try:
        if x == 1:
            a()
        if x == 2:
            b()
        if x == 3:
            c()
    except Exception as excp:
        stack = traceback.extract_stack()[:-3] + traceback.extract_tb(excp.__traceback__) 
        
        (filename, line, procname, text) = stack[-1]
        print (f" func {procname}")# 
       
    
        raise Exception("Problem in function")
    
    

    【讨论】:

    • 你能说得更具体些吗?哪部分代码与Python3不兼容?
    • print 语句应该有括号。
    • 我只是编辑我的代码
    【解决方案4】:

    您可以定义一个装饰器函数来包装感兴趣的函数,以便获得所需的信息(这是@chepner 的answer 的变体):

    
    def decorator(func):
        wraps(func)
        def wrapper(*args, **kwargs):
            global func_name
            func_name = func.__name__
            return func(*args, **kwargs)
        return wrapper
    
    
    @decorator
    def a():
        pass
    
    @decorator
    def b():
        raise RuntimeError('Uh Oh!')
    
    @decorator
    def a():
        pass
    
    
    x = 2
    
    try:
        if x == 1:
            a()
        if x == 2:
            b()
        if x == 3:
            c()
    except Exception as exc:
        raise Exception(f"Problem in function {func_name}()")
    

    【讨论】:

    • 这看起来很有趣。我现在正在尝试学习装饰器,看看是否可以实现。当您在答案中声明装饰器功能时,它是通用的吗?
    • 显示的装饰器是通用的,尽管它被硬编码以更新名为 func_name 的全局变量。
    【解决方案5】:

    这是一种通用方法,它使用 traceback.extract_tb() 函数从最近的异常中获取“预处理”堆栈跟踪条目的列表,其中包含 TracebackException 对象中的内容的子集(此与显示时回溯中的信息相同。最后一个条目包含有关最后一个调用的函数(即最近的函数)的信息,包括其名称。

    import traceback
    
    def a():
        pass
    
    def b():
        raise RuntimeError('Oops!')
    
    def a():
        pass
    
    
    x = 2
    try:
        if x == 1:
            a()
        if x == 2:
            b()
        if x == 3:
            c()
    except Exception as exc:
        filename, lineno, funcname, text = traceback.extract_tb(exc.__traceback__)[-1]
        raise Exception(f"Problem in function {funcname}()") from exc
    

    这里显示的输出:

    Traceback (most recent call last):
      File "display-which-function-caused-the-exception.py", line 22, in <module>
        b()
      File "display-which-function-caused-the-exception.py", line 10, in b
        raise RuntimeError('Oops!')
    RuntimeError: Oops!
    
    The above exception was the direct cause of the following exception:
    
    Traceback (most recent call last):
      File "display-which-function-caused-the-exception.py", line 27, in <module>
        raise Exception(f"Problem in function {funcname}()") from exc
    Exception: Problem in function b()
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-08-22
      • 1970-01-01
      • 2014-11-07
      • 1970-01-01
      • 2021-05-22
      • 1970-01-01
      相关资源
      最近更新 更多