Python“从"提升用法 [英] Python "raise from" usage

查看:25
本文介绍了Python“从"提升用法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Python 中的 raiseraise from 有什么区别?

尝试:引发值错误除了作为 e 的例外:引发索引错误

产生的结果

回溯(最近一次调用最后一次):文件tmp.py",第 2 行,在 <module> 中引发值错误值错误在处理上述异常的过程中,又发生了一个异常:回溯(最近一次调用最后一次):文件tmp.py",第 4 行,在 <module> 中引发索引错误索引错误

尝试:引发值错误除了作为 e 的例外:从 e 引发 IndexError

产生的结果

回溯(最近一次调用最后一次):文件tmp.py",第 2 行,在 <module> 中引发值错误值错误上述异常是以下异常的直接原因:回溯(最近一次调用最后一次):文件tmp.py",第 4 行,在 <module> 中从 e 引发 IndexError索引错误

解决方案

不同的是,当你使用 from 时,__cause__ 属性已设置并且消息指出异常是直接由引起的.如果省略 from 则不会设置 __cause__,但也可以设置 __context__ 属性,并且然后回溯将上下文显示为在处理其他事情时.

设置 __context__ 如果您在异常处理程序中使用了 raise;如果你在其他任何地方使用了 raise 也没有设置 __context__ .

如果设置了 __cause__,则异常也会设置 __suppress_context__ = True 标志;当 __suppress_context__ 设置为 True 时,打印回溯时会忽略 __context__.

当从您不想想要显示上下文的异常处理程序引发时(不希望在处理另一个异常时发生消息),然后使用 raise ... from None__suppress_context__ 设置为 True.

换句话说,Python 为异常设置了上下文,这样您就可以内省异常发生的位置,让您查看是否有另一个异常被它替换.您还可以向异常添加原因,使回溯明确关于另一个异常(使用不同的措辞),并忽略上下文(但在调试时仍然可以自省).使用 raise ... from None 可以抑制正在打印的上下文.

请参阅raise 声明文档:

<块引用>

from 子句用于异常链接:如果给定,第二个表达式必须是另一个异常类或实例,然后将其附加到引发的异常作为__cause__ 属性(可写).如果未处理引发的异常,则将打印两个异常:

<预><代码>>>>尝试:...打印(1/0)... 除了例外作为 exc:...从 exc 引发 RuntimeError(发生了一些不好的事情")...回溯(最近一次调用最后一次):文件<stdin>",第 2 行,在 <module>ZeroDivisionError: int 除法或模数为零上述异常是以下异常的直接原因:回溯(最近一次调用最后一次):文件<stdin>",第 4 行,在 <module> 中.运行时错误:发生了一些不好的事情

如果在异常处理程序或 finally 子句中引发异常,则类似的机制会隐式工作:然后将先前的异常附加为新异常的 __context__ 属性:

<预><代码>>>>尝试:...打印(1/0)... 除了:... raise RuntimeError(发生了一些不好的事情")...回溯(最近一次调用最后一次):文件<stdin>",第 2 行,在 <module>ZeroDivisionError: int 除法或模数为零在处理上述异常的过程中,又发生了一个异常:回溯(最近一次调用最后一次):文件<stdin>",第 4 行,在 <module> 中.运行时错误:发生了一些不好的事情

另请参阅内置异常文档有关附加到异常的上下文和原因信息的详细信息.

What's the difference between raise and raise from in Python?

try:
    raise ValueError
except Exception as e:
    raise IndexError

which yields

Traceback (most recent call last):
  File "tmp.py", line 2, in <module>
    raise ValueError
ValueError

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "tmp.py", line 4, in <module>
    raise IndexError
IndexError

and

try:
    raise ValueError
except Exception as e:
    raise IndexError from e

which yields

Traceback (most recent call last):
  File "tmp.py", line 2, in <module>
    raise ValueError
ValueError

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "tmp.py", line 4, in <module>
    raise IndexError from e
IndexError

解决方案

The difference is that when you use from, the __cause__ attribute is set and the message states that the exception was directly caused by. If you omit the from then no __cause__ is set, but the __context__ attribute may be set as well, and the traceback then shows the context as during handling something else happened.

Setting the __context__ happens if you used raise in an exception handler; if you used raise anywhere else no __context__ is set either.

If a __cause__ is set, a __suppress_context__ = True flag is also set on the exception; when __suppress_context__ is set to True, the __context__ is ignored when printing a traceback.

When raising from a exception handler where you don't want to show the context (don't want a during handling another exception happened message), then use raise ... from None to set __suppress_context__ to True.

In other words, Python sets a context on exceptions so you can introspect where an exception was raised, letting you see if another exception was replaced by it. You can also add a cause to an exception, making the traceback explicit about the other exception (use different wording), and the context is ignored (but can still be introspected when debugging). Using raise ... from None lets you suppress the context being printed.

See the raise statement documenation:

The from clause is used for exception chaining: if given, the second expression must be another exception class or instance, which will then be attached to the raised exception as the __cause__ attribute (which is writable). If the raised exception is not handled, both exceptions will be printed:

>>> try:
...     print(1 / 0)
... except Exception as exc:
...     raise RuntimeError("Something bad happened") from exc
...
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
ZeroDivisionError: int division or modulo by zero

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "<stdin>", line 4, in <module>
RuntimeError: Something bad happened

A similar mechanism works implicitly if an exception is raised inside an exception handler or a finally clause: the previous exception is then attached as the new exception’s __context__ attribute:

>>> try:
...     print(1 / 0)
... except:
...     raise RuntimeError("Something bad happened")
...
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
ZeroDivisionError: int division or modulo by zero

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "<stdin>", line 4, in <module>
RuntimeError: Something bad happened

Also see the Built-in Exceptions documentation for details on the context and cause information attached to exceptions.

这篇关于Python“从"提升用法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆