dar*_*ine 154 python syntax exception-handling python-3.x
Python raise
和raise from
Python 之间的区别是什么?
try:
raise ValueError
except Exception as e:
raise IndexError
Run Code Online (Sandbox Code Playgroud)
产量
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
Run Code Online (Sandbox Code Playgroud)
和
try:
raise ValueError
except Exception as e:
raise IndexError from e
Run Code Online (Sandbox Code Playgroud)
产量
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
Run Code Online (Sandbox Code Playgroud)
Mar*_*ers 180
不同之处在于,在使用时from
,会设置__cause__
属性并且消息指出异常是由直接引起的.如果省略则设置from
no __cause__
,但也可以设置__context__
属性,然后traceback将在处理其他事件时显示上下文.
__context__
如果您raise
在异常处理程序中使用,则设置发生; 如果你raise
在其他地方使用过,也没有__context__
设置.
如果__cause__
设置了a,__suppress_context__ = True
则还在异常上设置标志; 如果__suppress_context__
设置为True
,__context__
则在打印回溯时将忽略该值.
从异常处理程序引发时,您不希望显示上下文(不希望处理期间发生另一个异常消息),然后使用raise ... from None
设置__suppress_context__
为True
.
换句话说,Python 在异常上设置了一个上下文,这样你就可以反省引发异常的位置,让你看看是否有另一个异常被它取代.您还可以向异常添加原因,使回溯显式关于另一个异常(使用不同的措辞),并忽略上下文(但在调试时仍然可以进行内省).使用raise ... from None
可以抑制正在打印的上下文.
请参阅raise
声明文件:
该
from
子句用于异常链接:如果给定,则第二个表达式必须是另一个异常类或实例,然后将其作为__cause__
属性(可写)附加到引发的异常.如果未处理引发的异常,则将打印两个异常:Run Code Online (Sandbox Code Playgroud)>>> 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
如果在异常处理程序中引发异常,则类似的机制会隐式工作:>然后将先前的异常附加为新异常的
finally
属性:Run Code Online (Sandbox Code Playgroud)>>> 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
另请参阅内置异常文档,以获取有关上下文的详细信息以及附加到异常的原因信息.
Mag*_*ero 19
2005 年,PEP 3134、异常链和嵌入式回溯引入了异常链:
\nraise EXCEPTION
或隐式 raise (__context__
属性)的隐式链接;raise EXCEPTION from CAUSE
(__cause__
属性)的显式链接。\n\n动机
\n在处理一个异常(异常A)的过程中,有可能发生另一异常(异常B)。在今天\xe2\x80\x99s的Python(版本2.4)中,如果发生这种情况,异常B会向外传播,异常A会丢失。为了调试问题,了解这两个异常很有用。该
\n__context__
属性自动保留此信息。有时,异常处理程序有意重新引发异常可能很有用,可以提供额外的信息,也可以将异常转换为另一种类型。该
\n__cause__
属性提供了一种显式的方式来记录异常的直接原因。[\xe2\x80\xa6]
\n隐式异常链接
\n下面是一个例子来说明该
\n__context__
属性:Run Code Online (Sandbox Code Playgroud)\ndef compute(a, b):\n try:\n a/b\n except Exception, exc:\n log(exc)\n\ndef log(exc):\n file = open(\'logfile.txt\') # oops, forgot the \'w\'\n print >>file, exc\n file.close()\n
调用
\ncompute(0, 0)
会导致ZeroDivisionError
. 该compute()
函数捕获此异常并调用log(exc)
,但当该log()
函数尝试写入未打开用于写入的\xe2\x80\x99t 文件时,也会引发异常。在今天的\xe2\x80\x99s Python 中,调用者
\ncompute()
会抛出一个IOError
. 丢失ZeroDivisionError
了。通过建议的更改, 的实例IOError
具有__context__
保留ZeroDivisionError
.[\xe2\x80\xa6]
\n显式异常链接
\n异常对象的属性
\n__cause__
始终初始化为None
。它由新的语句形式设置raise
:Run Code Online (Sandbox Code Playgroud)\nraise EXCEPTION from CAUSE\n
这相当于:
\nRun Code Online (Sandbox Code Playgroud)\nexc = EXCEPTION\nexc.__cause__ = CAUSE\nraise exc\n
在下面的示例中,数据库提供了几种不同类型存储的实现,其中文件存储是一种。数据库设计者希望错误作为
\nDatabaseError
对象传播,以便客户端不必了解特定于存储的详细信息,但又不想丢失底层错误信息。Run Code Online (Sandbox Code Playgroud)\nclass DatabaseError(Exception):\n pass\n\nclass FileDatabase(Database):\n def __init__(self, filename):\n try:\n self.file = open(filename)\n except IOError, exc:\n raise DatabaseError(\'failed to open\') from exc\n
如果对 的调用
\nopen()
引发异常,则问题将报告为 aDatabaseError
,并带有一个将 揭示为原始原因的__cause__
属性。IOError
增强报告功能
\n默认异常处理程序将被修改以报告链式异常。
\n__cause__
通过遵循和属性来遍历异常链__context__
,并__cause__
优先考虑。为了与回溯的时间顺序保持一致,最近引发的异常显示在最后;也就是说,显示从最内层异常的描述开始,并将链备份到最外层异常。回溯的格式与往常一样,包含以下行之一:\n\n上述异常是导致以下异常的直接原因:
\n或者
\n\n\n在处理上述异常的过程中,又出现了一个异常:
\n\n
__cause__
回溯之间,取决于它们是否由或分别链接__context__
。以下是该过程的草图:Run Code Online (Sandbox Code Playgroud)\ndef print_chain(exc):\n if exc.__cause__:\n print_chain(exc.__cause__)\n print \'\\nThe above exception was the direct cause...\'\n elif exc.__context__:\n print_chain(exc.__context__)\n print \'\\nDuring handling of the above exception, ...\'\n print_exc(exc)\n
[\xe2\x80\xa6]
\n
2012 年,PEP 415“使用异常属性实现上下文抑制”raise EXCEPTION from None
引入了使用显式(属性)的异常上下文抑制__suppress_context__
。
\n\n提议
\n将引入
\nBaseException
,上的新属性。__suppress_context__
每当__cause__
设置时,__suppress_context__
都会设置为True
。特别是,raise exc from cause
语法将设置exc.__suppress_context__
为True
. 异常打印代码将检查该属性以确定是否打印上下文和原因。__cause__
将回归其最初的目的和价值。\n
__suppress_context__
异常属性具有优先权print_line_and_file
。总而言之,
\nraise exc from cause
将相当于:Run Code Online (Sandbox Code Playgroud)\nexc.__cause__ = cause\nraise exc\n
其中
\nexc.__cause__ = cause
隐式设置exc.__suppress_context__
.
因此,在 PEP 415 中,PEP 3134 中给出的默认异常处理程序(其工作是报告异常)的过程概述如下:
\ndef print_chain(exc):\n if exc.__cause__:\n print_chain(exc.__cause__)\n print \'\\nThe above exception was the direct cause...\'\n elif exc.__context__ and not exc.__suppress_context__:\n print_chain(exc.__context__)\n print \'\\nDuring handling of the above exception, ...\'\n print_exc(exc)\n
Run Code Online (Sandbox Code Playgroud)\n
最短的答案。PEP-3134说明了一切。raise Exception from e
设置__cause__
新异常的字段。
来自同一个 PEP 的更长答案:
__context__
字段将隐式设置为except:
块内的原始错误,除非被告知不要使用__suppress_context__ = True
。__cause__
就像上下文一样,但必须使用from
语法显式设置traceback
raise
当您在块内调用时将始终链接except
。except: pass
您可以通过a)吞掉异常或直接搞乱来摆脱回溯sys.exc_info()
。长答案
import traceback
import sys
class CustomError(Exception):
def __init__(self):
super().__init__("custom")
def print_exception(func):
print(f"\n\n\nEXECURTING FUNCTION '{func.__name__}' \n")
try:
func()
except Exception as e:
"Here is result of our actions:"
print(f"\tException type: '{type(e)}'")
print(f"\tException message: '{e}'")
print(f"\tException context: '{e.__context__}'")
print(f"\tContext type: '{type(e.__context__)}'")
print(f"\tException cause: '{e.__cause__}'")
print(f"\tCause type: '{type(e.__cause__)}'")
print("\nTRACEBACKSTART>>>")
traceback.print_exc()
print("<<<TRACEBACKEND")
def original_error_emitter():
x = {}
print(x.does_not_exist)
def vanilla_catch_swallow():
"""Nothing is expected to happen"""
try:
original_error_emitter()
except Exception as e:
pass
def vanilla_catch_reraise():
"""Nothing is expected to happen"""
try:
original_error_emitter()
except Exception as e:
raise e
def catch_replace():
"""Nothing is expected to happen"""
try:
original_error_emitter()
except Exception as e:
raise CustomError()
def catch_replace_with_from():
"""Nothing is expected to happen"""
try:
original_error_emitter()
except Exception as e:
raise CustomError() from e
def catch_reset_trace():
saw_an_error = False
try:
original_error_emitter()
except Exception as e:
saw_an_error = True
if saw_an_error:
raise CustomError()
print("Note: This will print nothing")
print_exception(vanilla_catch_swallow)
print("Note: This will print AttributeError and 1 stack trace")
print_exception(vanilla_catch_reraise)
print("Note: This will print CustomError with no context but 2 stack traces")
print_exception(catch_replace)
print("Note: This will print CustomError with AttributeError context and 2 stack traces")
print_exception(catch_replace_with_from)
print("Note: This will brake traceback chain")
print_exception(catch_reset_trace)
Run Code Online (Sandbox Code Playgroud)
将产生以下输出:
Note: This will print nothing
EXECURTING FUNCTION 'vanilla_catch_swallow'
Note: This will print AttributeError and 1 stack trace
EXECURTING FUNCTION 'vanilla_catch_reraise'
Exception type: '<class 'AttributeError'>'
Exception message: ''dict' object has no attribute 'does_not_exist''
Exception context: 'None'
Context type: '<class 'NoneType'>'
Exception cause: 'None'
Cause type: '<class 'NoneType'>'
TRACEBACKSTART>>>
Traceback (most recent call last):
File "/Users/eugene.selivonchyk/repo/experiments/exceptions.py", line 11, in print_exception
func()
File "/Users/eugene.selivonchyk/repo/experiments/exceptions.py", line 41, in vanilla_catch_reraise
raise e
File "/Users/eugene.selivonchyk/repo/experiments/exceptions.py", line 39, in vanilla_catch_reraise
original_error_emitter()
File "/Users/eugene.selivonchyk/repo/experiments/exceptions.py", line 27, in original_error_emitter
print(x.does_not_exist)
AttributeError: 'dict' object has no attribute 'does_not_exist'
<<<TRACEBACKEND
Note: This will print CustomError with no context but 2 stack traces
EXECURTING FUNCTION 'catch_replace'
Exception type: '<class '__main__.CustomError'>'
Exception message: 'custom'
Exception context: ''dict' object has no attribute 'does_not_exist''
Context type: '<class 'AttributeError'>'
Exception cause: 'None'
Cause type: '<class 'NoneType'>'
TRACEBACKSTART>>>
Traceback (most recent call last):
File "/Users/eugene.selivonchyk/repo/experiments/exceptions.py", line 46, in catch_replace
original_error_emitter()
File "/Users/eugene.selivonchyk/repo/experiments/exceptions.py", line 27, in original_error_emitter
print(x.does_not_exist)
AttributeError: 'dict' object has no attribute 'does_not_exist'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/Users/eugene.selivonchyk/repo/experiments/exceptions.py", line 11, in print_exception
func()
File "/Users/eugene.selivonchyk/repo/experiments/exceptions.py", line 48, in catch_replace
raise CustomError()
CustomError: custom
<<<TRACEBACKEND
Note: This will print CustomError with AttributeError context and 2 stack traces
EXECURTING FUNCTION 'catch_replace_with_from'
Exception type: '<class '__main__.CustomError'>'
Exception message: 'custom'
Exception context: ''dict' object has no attribute 'does_not_exist''
Context type: '<class 'AttributeError'>'
Exception cause: ''dict' object has no attribute 'does_not_exist''
Cause type: '<class 'AttributeError'>'
TRACEBACKSTART>>>
Traceback (most recent call last):
File "/Users/eugene.selivonchyk/repo/experiments/exceptions.py", line 53, in catch_replace_with_from
original_error_emitter()
File "/Users/eugene.selivonchyk/repo/experiments/exceptions.py", line 27, in original_error_emitter
print(x.does_not_exist)
AttributeError: 'dict' object has no attribute 'does_not_exist'
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "/Users/eugene.selivonchyk/repo/experiments/exceptions.py", line 11, in print_exception
func()
File "/Users/eugene.selivonchyk/repo/experiments/exceptions.py", line 55, in catch_replace_with_from
raise CustomError() from e
CustomError: custom
<<<TRACEBACKEND
Note: This will brake traceback chain
EXECURTING FUNCTION 'catch_reset_trace'
Exception type: '<class '__main__.CustomError'>'
Exception message: 'custom'
Exception context: 'None'
Context type: '<class 'NoneType'>'
Exception cause: 'None'
Cause type: '<class 'NoneType'>'
TRACEBACKSTART>>>
Traceback (most recent call last):
File "/Users/eugene.selivonchyk/repo/experiments/exceptions.py", line 11, in print_exception
func()
File "/Users/eugene.selivonchyk/repo/experiments/exceptions.py", line 64, in catch_reset_trace
raise CustomError()
CustomError: custom
<<<TRACEBACKEND
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
39690 次 |
最近记录: |