无争议地提高

时间:2013-08-01 18:25:40

标签: python exception

没有参数的raise语句的documentation表示

  

如果没有表达式,则raise重新引发当前作用域中活动的最后一个异常。

我曾经认为这意味着当前函数必须执行except子句。在阅读this question并尝试一点之后,我认为这意味着堆栈上的任何函数都必须执行except子句,但我不确定。另外,我已经意识到我不知道堆栈跟踪如何使用no-arg raise:

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

def g():
  raise

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

这看起来不像初始加注时的堆栈,或者重新加注时的堆栈,或者两个堆栈的串联,或者我能理解的任何东西。

我是否正确地寻找执行except子句的堆栈上的任何函数?此外,堆栈跟踪如何在重新加载时起作用?

3 个答案:

答案 0 :(得分:15)

当你raise没有参数时,解释器会查找最后异常引发并处理。然后它就像使用raise一样使用最新的异常类型,值和回溯。

它存储在当前线程的解释器状态中,可以使用sys.exc_info()检索相同的信息。通过'处理'我的意思是一个except子句捕获了异常。引用try statement documentation

  

在执行except子句的套件之前,有关异常的详细信息被分配给sys模块中的三个变量:sys.exc_type接收标识异常的对象; sys.exc_value收到异常的参数; sys.exc_traceback收到一个回溯对象(请参阅The standard type hierarchy标识程序中发生异常的点。这些详细信息也可以通过sys.exc_info()函数获得,该函数返回一个元组{{1} }。

请参阅Python评估循环中的implemenation notes(C代码),具体来说:

  

第二个     bullet是为了向后兼容:它是(并且是)常见的     具有在捕获异常时调用的函数,以及     让该函数通过sys.exc_ZZZ访问捕获的异常。     (例如:traceback.print_exc())。

追溯反映了您如何准确地进行重新加注。它是当前堆栈(第10行调用(exc_type, exc_value, exc_traceback),第5行调用f())加上引发的异常的原始位置:第3行。

答案 1 :(得分:2)

事实证明,Python使用了一种令人惊讶的方式来建立追溯。除了在异常创建时(like Java)或引发异常时(就像我以前认为的那样)构建整个堆栈跟踪,Python会在异常冒泡时一次建立一帧局部回溯。

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(或Python 2上的两个参数的形式),Python字节码解释器循环执行PyTraceback_Here,将新的头添加到表示堆栈跟踪的跟踪对象的链接列表中。 (在Python 2上,0参数<android.support.v7.widget.Toolbar ... app:titleTextAppearance="@style/Toolbar.TitleText"/> 和3参数raise跳过此步骤。)

Python维护了每个线程的异常(和回溯)堆栈,这些异常(和回溯)由尚未完成执行的raiseexcept块挂起。 0参数finally restores,即使raiseexcept在不同的函数中,也由堆栈顶部的条目表示的异常(和回溯)。

finally执行其f时:

raise

Python建立与该行相对应的回溯:

raise Exception

File "foo", line 3, in f raise Exception 执行0参数g时,将还原此追溯,但不会为0参数raise行添加任何条目。

此后,随着异常在整个堆栈的其余部分冒出,将raiseg()调用的条目添加到堆栈跟踪中,从而显示最终的堆栈跟踪: / p>

f()

答案 2 :(得分:-1)

以下代码可能有助于您了解 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')