Python 毫无争议地提出

Python 毫无争议地提出,python,exception,Python,Exception,没有参数的raise语句的 如果不存在表达式,raise将重新引发当前作用域中活动的最后一个异常 我过去认为这意味着当前函数必须执行except子句。在阅读并进行了一些实验之后,我认为这意味着堆栈上的任何函数都必须执行一个子句,除了子句,但我不确定。此外,我意识到我不知道堆栈跟踪如何在无arg提升的情况下工作: def f(): try: raise Exception except: g() def g(): raise f() 产生 Traceback (m

没有参数的raise语句的

如果不存在表达式,raise将重新引发当前作用域中活动的最后一个异常

我过去认为这意味着当前函数必须执行
except
子句。在阅读并进行了一些实验之后,我认为这意味着堆栈上的任何函数都必须执行一个
子句,除了
子句,但我不确定。此外,我意识到我不知道堆栈跟踪如何在无arg提升的情况下工作:

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
回溯(最近一次呼叫最后一次):
文件“foo”,第10行,在
f()
文件“foo”,第5行,在f中
g()
文件“foo”,第3行,在f中
引发异常
例外情况
这看起来不像初始提升时的堆栈,或者重新提升时的堆栈,或者两个堆栈的串联,或者我能理解的任何东西


我在堆栈上查找执行
except
子句的任何函数的无参数提升是否正确?另外,堆栈跟踪如何在重新调用上工作?

当您在没有参数的情况下调用时,解释器将查找最后一个调用并处理的异常。然后,它的作用与对最近的异常类型、值和回溯使用
raise
时相同

这将存储在当前线程的解释器状态中,并且可以使用来检索相同的信息。“handled”是指except子句捕获了异常。引述:

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

请参见Python评估循环(C代码)中的,具体如下:

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


回溯反映了您如何准确地到达重新提升。它是当前堆栈(第10行调用
f()
,第5行调用
g()
)加上引发异常的原始位置:第3行。

事实证明,Python使用了一种令人惊讶的方法来构建回溯。它不是在创建异常()或引发异常时构建整个堆栈跟踪(就像我过去认为的那样),而是在异常冒泡时一次构建一个部分回溯框架

(或者在Python2上是双参数形式),执行Python字节码解释器循环以向表示堆栈跟踪的回溯对象的链接列表中添加一个新的头。(Python2上的0参数
raise
,和3参数
raise
,跳过此步骤。)

Python维护由
暂停的每个线程异常(和回溯)堆栈,除了
最后
尚未完成执行的块。0参数
引发异常(和回溯)由该堆栈上的顶部条目表示,即使
except
finally
处于不同的函数中

f
执行其
raise
时:

raise Exception
Python构建了与该行对应的回溯:

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

之后,当异常在堆栈的其余部分冒泡时,将
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
回溯(最近一次呼叫最后一次):
文件“foo”,第10行,在
f()
文件“foo”,第5行,在f中
g()
文件“foo”,第3行,在f中
引发异常
例外情况

我认为这是不对的,但在交互模式下处理异常状态的方式似乎与在执行脚本时不同。在except子句后放置reraise在函数或脚本中的效果与在交互会话的顶层不同。@user2357112:不,不是。回溯信息是稀疏的因为没有要内省和包含的源代码,但行号完全相同。真的吗?因为当我尝试它时,捕获异常并在except子句结束后尝试重新激活它会引发
TypeError:异常必须是旧式类或派生自BaseException,而不是interact顶层的NoneType
ive会话,但当我将其放入脚本或函数中时,它成功地重新验证了上一个错误。@user2357112:在Python 2.7和3.3中,将操作代码复制并粘贴到解释器对我来说很好。@user2357112:请注意,
except
子句显式地清除捕获异常的本地名称,以防止内存泄漏。它是It’值得注意的是,所有这些内容都在Python 3.x中进行了清理,并有了更好的文档记录。因此,您可能会更好地了解3.3而不是2.7。(IIRC,
raise
的措辞本身并没有更好,但“活动异常”的概念实际上是在某个地方或其他地方定义的,所以您只需搜索它,而不是试图猜测它的含义……)raise NameError(“任何文本”)