简体   繁体   English

毫无争议地提出

[英]raise with no argument

The documentation for the raise statement with no arguments says没有参数的 raise 语句的文档

If no expressions are present, raise re-raises the last exception that was active in the current scope.如果不存在表达式, raise 重新引发当前作用域中活动的最后一个异常。

I used to think that meant that the current function had to be executing an except clause.我曾经认为这意味着当前函数必须执行一个except子句。 After reading this question and experimenting a little, I think it means that any function on the stack has to be executing an except clause, but I'm not sure.在阅读了这个问题并进行了一些试验后,我认为这意味着堆栈上的任何函数都必须执行一个except子句,但我不确定。 Also, I've realized I have no idea how the stack trace works with a no-arg raise:另外,我意识到我不知道堆栈跟踪如何与无参数加注一起工作:

def f():
  try:
    raise Exception
  except:
    g()

def g():
  raise

f()

produces产生

Traceback (most recent call last):
  File "foo", line 10, in <module>
    f()
  File "foo", line 5, in f
    g()
  File "foo", line 3, in f
    raise Exception
Exception

That doesn't look like the stack at the time of the initial raise, or the stack at the time of the re-raise, or the concatenation of both stacks, or anything I can make sense of.这看起来不像初始加注时的筹码,或者再次加注时的筹码,或者两个筹码的串联,或者任何我能理解的东西。

Am I right about a no-arg raise looking for any function on the stack executing an except clause?关于在堆栈上寻找任何函数执行一个except子句的无参数加注,我是否正确? Also, how does the stack trace work on a reraise?另外,堆栈跟踪如何在重新加注时工作?

When you raise without arguments, the interpreter looks for the last exception raised and handled .当你raise不带参数的解释看起来在过去的异常升高和处理 It then acts the same as if you used raise with the most recent exception type, value and traceback.然后它的行为与您使用raise与最新的异常类型、值和回溯相同。

This is stored in the interpreter state for the current thread, and the same information can be retrieved using sys.exc_info() .这存储在当前线程的解释器状态中,可以使用sys.exc_info()检索相同的信息。 By 'handled' I mean that an except clause caught the exception.通过“处理”,我的意思是一个except 子句捕获了异常。 Quoting the try statement documentation :引用try语句文档

Before an except clause's suite is executed, details about the exception are assigned to three variables in the sys module: sys.exc_type receives the object identifying the exception;在执行except 子句的套件之前,有关异常的详细信息被分配给sys模块中的三个变量: sys.exc_type接收标识异常的对象; sys.exc_value receives the exception's parameter; sys.exc_value接收异常的参数; sys.exc_traceback receives a traceback object (see section The standard type hierarchy identifying the point in the program where the exception occurred. These details are also available through the sys.exc_info() function, which returns a tuple (exc_type, exc_value, exc_traceback) . sys.exc_traceback接收一个回溯对象(参见标准类型层次结构,标识程序中发生异常的点。这些细节也可以通过sys.exc_info()函数获得,该函数返回一个元组(exc_type, exc_value, exc_traceback) .

See the implemenation notes in the Python evaluation loop (C code), specifically:参见 Python 评估循环(C 代码)中的实现说明,具体如下:

The second bullet was for backwards compatibility: it was (and is) common to have a function that is called when an exception is caught, and to have that function access the caught exception via sys.exc_ZZZ.第二个要点是为了向后兼容:在捕获异常时调用一个函数,并让该函数通过 sys.exc_ZZZ 访问捕获的异常,这在过去(并且现在)很常见。 (Example: traceback.print_exc()). (例如:traceback.print_exc())。

The traceback reflects how you came to the re-raise accurately.回溯反映了你如何准确地再次加注。 It is the current stack (line 10 calling f() , line 5 calling g() ) plus the original location of the exception raised: line 3.它是当前堆栈(第 10 行调用f() ,第 5 行调用g() )加上引发异常的原始位置:第 3 行。

It turns out Python uses a surprising way of building tracebacks.事实证明,Python 使用了一种令人惊讶的方式来构建回溯。 Rather than building the whole stack trace on exception creation ( like Java ) or when an exception is raised (like I used to think), Python builds up a partial traceback one frame at a time as the exception bubbles up. Python 不是在异常创建时( 如 Java )或在引发异常时(如我以前认为的)构建整个堆栈跟踪,而是在异常冒泡时一次一帧地构建部分回溯。

Every time an exception bubbles up to a new stack frame, as well as when an exception is raised with the one-argument form of raise (or the two-argument form, on Python 2), the Python bytecode interpreter loop executes PyTraceback_Here to add a new head to the linked list of traceback objects representing the stack trace. 每次异常冒泡到新的堆栈帧时,以及当异常以单参数形式raise (或双参数形式,在 Python 2 上) PyTraceback_Here ,Python 字节码解释器循环执行PyTraceback_Here以添加表示堆栈跟踪的回溯对象链表的新头。 (0-argument raise , and 3-argument raise on Python 2, skip this step.) (Python 2 上的 0-argument raise和 3-argument raise ,跳过这一步。)

Python maintains a per-thread stack of exceptions (and tracebacks) suspended by except and finally blocks that haven't finished executing. Python 维护着一个由未完成执行的exceptfinally块挂起的每个线程的异常(和回溯)堆栈。 0-argument raise restores the exception (and traceback) represented by the top entry on this stack, even if the except or finally is in a different function. 0 参数raise 恢复由该堆栈顶部条目表示的异常(和回溯),即使exceptfinally在不同的函数中。

When f executes its raise :f执行它的raise

raise Exception

Python builds a traceback corresponding to just that line: Python 构建了一个对应于该行的回溯:

  File "foo", line 3, in f
    raise Exception

When g executes 0-argument raise , this traceback is restored, but no entry is added for the 0-argument raise line.g执行 0-argument raise ,这个回溯被恢复,但没有为 0-argument raise行添加任何条目。

Afterwards, as the exception bubbles up through the rest of the stack, entries for the g() and f() calls are added to the stack trace, resulting in the final stack trace that gets displayed:之后,当异常在堆栈的其余部分冒泡时, g()f()调用的条目被添加到堆栈跟踪中,导致显示的最终堆栈跟踪:

Traceback (most recent call last):
  File "foo", line 10, in <module>
    f()
  File "foo", line 5, in f
    g()
  File "foo", line 3, in f
    raise Exception
Exception

The following piece of code might help you understand how the raise keyword works:以下代码可能会帮助您了解 raise 关键字的工作原理:

def fun(n):
    try:
        return 0 / n
    except:
        print('an exception raised:')
        raise

try:
    fun(0)
except:
    print('cannot divide by zero')

try:
    fun('0')
except:
    print('cannot divide by a string')

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM