Manually raising (throwing) an exception in Python
如何在Python中引发异常,以便稍后通过
How do I manually throw/raise an exception in Python?
使用语义上适合您的问题的最特定的异常构造函数。
信息要具体,例如:
1 | raise ValueError('A very specific bad thing happened.') |
不引发泛型异常
避免引发泛型异常。要捕获它,您必须捕获子类化它的所有其他更具体的异常。
问题1:隐藏bug1 | raise Exception('I know Python!') # Don't! If you catch, likely to hide bugs. |
例如:
1 2 3 4 5 6 7 8 9 | def demo_bad_catch(): try: raise ValueError('Represents a hidden bug, do not catch this') raise Exception('This is the exception you expect to handle') except Exception as error: print('Caught this error: ' + repr(error)) >>> demo_bad_catch() Caught this error: ValueError('Represents a hidden bug, do not catch this',) |
问题2:不会捕捉到
更具体的捕获不会捕获一般的异常:
1 2 3 4 5 6 7 8 9 10 11 12 | def demo_no_catch(): try: raise Exception('general exceptions not caught by specific handling') except ValueError as e: print('we will not catch exception: Exception') >>> demo_no_catch() Traceback (most recent call last): File"<stdin>", line 1, in <module> File"<stdin>", line 3, in demo_no_catch Exception: general exceptions not caught by specific handling |
最佳实践:
相反,使用语义上适合您的问题的最特定的异常构造函数。
1 | raise ValueError('A very specific bad thing happened') |
这也方便地允许任意数量的参数传递给构造函数:
1 | raise ValueError('A very specific bad thing happened', 'foo', 'bar', 'baz') |
异常对象上的
1 2 3 4 | try: some_code_that_may_raise_our_value_error() except ValueError as err: print(err.args) |
打印
1 | ('message', 'foo', 'bar', 'baz') |
在Python 2.5中,一个实际的
例如,在except子句中,您可能希望记录发生的特定类型错误,然后重新引发。保存堆栈跟踪的最佳方法是使用一条bare raise语句。例如:
1 2 3 4 5 6 7 8 | logger = logging.getLogger(__name__) try: do_something_in_app_that_breaks_easily() except AppError as error: logger.error(error) raise # just this! # raise AppError # Don't do this, you'll lose the stack trace! |
不要修改你的错误…但如果你坚持的话。
您可以使用
解释——
1 | type, value, traceback = sys.exc_info() |
这是Python 2的语法-注意,这与Python 3不兼容:
1 2 3 | raise AppError, error, sys.exc_info()[2] # avoid this. # Equivalently, as error *is* the second object: raise sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2] |
如果你愿意,你可以修改你的新加薪发生了什么-例如,为实例设置新的args:
1 2 3 4 5 6 7 8 9 10 | def error(): raise ValueError('oops!') def catch_error_modify_message(): try: error() except ValueError: error_type, error_instance, traceback = sys.exc_info() error_instance.args = (error_instance.args[0] + ' <modification>',) raise error_type, error_instance, traceback |
我们在修改args时保留了整个回溯。注意,这不是最佳实践,而且在python3中它是无效的语法(这使得保持兼容性变得更加困难)。
1 2 3 4 5 6 | >>> catch_error_modify_message() Traceback (most recent call last): File"<stdin>", line 1, in <module> File"<stdin>", line 3, in catch_error_modify_message File"<stdin>", line 2, in error ValueError: oops! <modification> |
在Python 3:
1 | raise error.with_traceback(sys.exc_info()[2]) |
再次声明:避免手动操作回溯。它的效率更低,更容易出错。如果你使用线程和
在python3中,你可以把异常链起来,这样可以保存回溯:
1 | raise RuntimeError('specific message') from error |
请注意:
这允许更改引发的错误类型这与python2不兼容。弃用方法:
这些可以很容易地隐藏,甚至进入生产代码。您希望引发异常,执行这些操作将引发异常,但不是预期的异常!
以下内容在python2中有效,但在python3中无效:
1 | raise ValueError, 'message' # Don't do this, it's deprecated! |
只有在更老版本的Python(2.4或更低版本)中才有效,您可能仍然会看到有人在提升字符串:
1 | raise 'message' # really really wrong. don't do this. |
在所有现代版本中,这实际上会引发一个类型错误,因为您没有引发BaseException类型。如果您没有检查正确的异常,并且没有意识到问题的审查员,那么它可能会进入生产。
< / hh2范例用法>
我提出异常,警告消费者我的API如果他们使用不当:
1 2 3 4 | def api_func(foo): '''foo should be either 'baz' or 'bar'. returns something very useful.''' if foo not in _ALLOWED_ARGS: raise ValueError('{foo} wrong, use"baz" or"bar"'.format(foo=repr(foo))) |
当apropos时,创建您自己的错误类型
"I want to make an error on purpose, so that it would go into the except"
你可以创建你自己的错误类型,如果你想指出你的应用程序有什么特定的错误,只要子类化异常层次结构中的适当点:
1 2 | class MyAppLookupError(LookupError): '''raise this when there's a lookup error for my app''' |
和用法:
1 2 | if important_key not in resource_dict and not ok_to_be_missing: raise MyAppLookupError('resource is missing, and that is not ok.') |
DON'T DO THIS. Raising a bare
Exception is absolutely not the right thing to do; see Aaron Hall's excellent answer instead.
没有什么比这更像蟒蛇的了:
1 | raise Exception("I know python!") |
如果您想了解更多信息,请参阅python的raise语句文档。
对于一些常见的情况,您需要抛出一个异常来响应一些意外的情况,而您从来没有打算捕获异常,而是简单地快速失败,使您能够从那里调试,如果它发生了——最合乎逻辑的一个似乎是
1 2 3 4 5 6 | if 0 < distance <= RADIUS: #Do something. elif RADIUS < distance: #Do something. else: raise AssertionError("Unexpected value of 'distance'!", distance) |
在Python3中有4种不同的语法用于rasing exception:
1 2 3 4 | 1. raise exception 2. raise exception (args) 3. raise 4. raise exception (args) from original_exception |
1. raise exception vs. 2. raise exception (args)
如果使用
1 2 3 4 5 6 7 8 9 10 11 12 13 | #raise exception (args) try: raise ValueError("I have raised an Exception") except ValueError as exp: print ("Error", exp) # Output -> Error I have raised an Exception #raise execption try: raise ValueError except ValueError as exp: print ("Error", exp) # Output -> Error |
3.raise
没有任何参数的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | def somefunction(): print("some cleaning") a=10 b=0 result=None try: result=a/b print(result) except Exception: #Output -> somefunction() #some cleaning raise #Traceback (most recent call last): #File"python", line 8, in <module> #ZeroDivisionError: division by zero |
4. raise exception (args) from original_exception
此语句用于创建异常链,其中响应另一个异常而引发的异常可以包含原始异常的详细信息——如下面的示例所示。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | class MyCustomException(Exception): pass a=10 b=0 reuslt=None try: try: result=a/b except ZeroDivisionError as exp: print("ZeroDivisionError --",exp) raise MyCustomException("Zero Division") from exp except MyCustomException as exp: print("MyException",exp) print(exp.__cause__) |
输出:
1 2 3 | ZeroDivisionError -- division by zero MyException Zero Division division by zero |
先阅读现有的答案,这只是一个附录。
注意,可以使用参数或不使用参数引发异常。
例子:
1 | raise SystemExit |
退出程序,但您可能想知道发生了什么。你可以用这个。
1 | raise SystemExit("program exited") |
这将打印"程序退出"到stderr之前关闭程序。
抛出异常的另一种方法是
1 2 3 4 5 6 7 8 9 | def avg(marks): assert len(marks) != 0,"List is empty." return sum(marks)/len(marks) mark2 = [55,88,78,90,79] print("Average of mark2:",avg(mark2)) mark1 = [] print("Average of mark1:",avg(mark1)) |
注意:有时确实需要处理泛型异常。如果您正在处理一堆文件并记录您的错误,那么您可能希望捕捉发生在文件中的任何错误,并将其记录下来,然后继续处理其余的文件。在这种情况下,使用