How can I raise an exception in Python so that it can later be caught via an except
block?
如何在Python中引发一个异常,以便以后可以通过一个except块捕获它?
5 个解决方案
#1
1784
How do I manually throw/raise an exception in Python?
Use the most specific Exception constructor that semantically fits your issue.
使用语义上适合您的问题的最特定的异常构造函数。
Be specific in your message, e.g.:
在你的信息中要具体,例如:
raise ValueError('A very specific bad thing happened.')
Don't raise generic exceptions
Avoid raising a generic Exception. To catch it, you'll have to catch all other more specific exceptions that subclass it.
避免引发通用异常。要捕获它,您必须捕获所有其他更具体的子类。
Problem 1: Hiding bugs
raise Exception('I know Python!') # Don't! If you catch, likely to hide bugs.
For example:
例如:
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',)
Problem 2: Won't catch
and more specific catches won't catch the general exception:
更具体的渔获量不会捕获一般的例外:
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
Best Practices: raise
statement
Instead, use the most specific Exception constructor that semantically fits your issue.
相反,使用语义上适合您的问题的最特定的异常构造函数。
raise ValueError('A very specific bad thing happened')
which also handily allows an arbitrary number of arguments to be passed to the constructor:
它也方便地允许任意数量的参数传递给构造函数:
raise ValueError('A very specific bad thing happened', 'foo', 'bar', 'baz')
These arguments are accessed by the args
attribute on the Exception object. For example:
这些参数由异常对象上的args属性访问。例如:
try:
some_code_that_may_raise_our_value_error()
except ValueError as err:
print(err.args)
prints
打印
('message', 'foo', 'bar', 'baz')
In Python 2.5, an actual message
attribute was added to BaseException in favor of encouraging users to subclass Exceptions and stop using args
, but the introduction of message
and the original deprecation of args has been retracted.
在Python 2.5中,一个实际的消息属性被添加到BaseException,支持鼓励用户对异常进行子类化,并停止使用args,但是消息的引入和args的原始弃用已经被撤销。
Best Practices: except
clause
When inside an except clause, you might want to, for example, log that a specific type of error happened, and then re-raise. The best way to do this while preserving the stack trace is to use a bare raise statement. For example:
当在一个except子句中时,您可能希望,例如,记录某个特定类型的错误发生,然后重新引发。保存堆栈跟踪的最佳方法是使用一个简单的raise语句。例如:
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!
Don't modify your errors... but if you insist.
You can preserve the stacktrace (and error value) with sys.exc_info()
, but this is way more error prone and has compatibility problems between Python 2 and 3, prefer to use a bare raise
to re-raise.
您可以使用sys.exc_info()来保存stacktrace(和错误值),但是这更容易出错,并且在Python 2和3之间存在兼容性问题,更倾向于使用简单的raise来重新提高。
To explain - the sys.exc_info()
returns the type, value, and traceback.
要解释——sys.exc_info()返回类型、值和回溯。
type, value, traceback = sys.exc_info()
This is the syntax in Python 2 - note this is not compatible with Python 3:
这是Python 2中的语法-注意,这与Python 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]
If you want to, you can modify what happens with your new raise - e.g. setting new args for the instance:
如果你想的话,你可以修改你的加薪计划——例如为这个例子设置新的args:
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
And we have preserved the whole traceback while modifying the args. Note that this is not a best practice and it is invalid syntax in Python 3 (making keeping compatibility much harder to work around).
我们在修改args时保留了整个回溯。注意,这不是最佳实践,而且在Python 3中是无效语法(使保持兼容性更加困难)。
>>> 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>
In Python 3:
在Python 3:
raise error.with_traceback(sys.exc_info()[2])
Again: avoid manually manipulating tracebacks. It's less efficient and more error prone. And if you're using threading and sys.exc_info
you may even get the wrong traceback (especially if you're using exception handling for control flow - which I'd personally tend to avoid.)
同样:避免手动操作回溯。它的效率更低,更容易出错。如果你使用的是线程和系统。您甚至可能会得到错误的回溯(特别是如果您在控制流中使用异常处理——我个人倾向于避免这种情况)。
Python 3, Exception chaining
In Python 3, you can chain Exceptions, which preserve tracebacks:
在Python 3中,可以对异常进行链式处理,这样可以保留回溯:
raise RuntimeError('specific message') from error
Be aware:
请注意:
- this does allow changing the error type raised, and
- 这确实允许更改引发的错误类型,并且
- this is not compatible with Python 2.
- 这与Python 2不兼容。
Deprecated Methods:
These can easily hide and even get into production code. You want to raise an exception, and doing them will raise an exception, but not the one intended!
它们可以很容易地隐藏,甚至进入生产代码。您想要引发一个异常,这样做将引发一个异常,但不是预期的异常!
Valid in Python 2, but not in Python 3 is the following:
在Python 2中有效,但在Python 3中无效的是:
raise ValueError, 'message' # Don't do this, it's deprecated!
Only valid in much older versions of Python (2.4 and lower), you may still see people raising strings:
只有在更老版本的Python(2.4和更低版本)中才有效,您仍然可以看到人们在提高字符串:
raise 'message' # really really wrong. don't do this.
In all modern versions, this will actually raise a TypeError, because you're not raising a BaseException type. If you're not checking for the right exception and don't have a reviewer that's aware of the issue, it could get into production.
在所有现代版本中,这实际上会引发一个TypeError,因为您没有引发一个BaseException类型。如果您没有检查正确的异常,并且没有意识到这个问题的检查器,那么它可以进入产品。
Example Usage
I raise Exceptions to warn consumers of my API if they're using it incorrectly:
如果用户使用我的API不正确,我就提出异常警告:
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)))
Create your own error types when apropos
"I want to make an error on purpose, so that it would go into the except"
"我想故意犯一个错误,这样它就会进入"
You can create your own error types, if you want to indicate something specific is wrong with your application, just subclass the appropriate point in the exception hierarchy:
您可以创建自己的错误类型,如果您想指示您的应用程序有什么特定的错误,只需将异常层次结构中的适当点子类化:
class MyAppLookupError(LookupError):
'''raise this when there's a lookup error for my app'''
and usage:
和用法:
if important_key not in resource_dict and not ok_to_be_missing:
raise MyAppLookupError('resource is missing, and that is not ok.')
#2
540
DON'T DO THIS. Raising a bare
Exception
is absolutely not the right thing to do; see Aaron Hall's excellent answer instead.不要这样做。提出一个纯粹的例外绝对不是正确的做法;看看艾伦·霍尔的精彩回答。
Can't get much more pythonic than this:
不能得到比这个更大的python:
raise Exception("I know python!")
See the raise statement docs for python if you'd like more info.
如果您想了解更多信息,请参阅python的raise语句文档。
#3
27
For the common case where you need to throw an exception in response to some unexpected conditions, and that you never intend to catch, but simply to fail fast to enable you to debug from there if it ever happens — the most logical one seems to be AssertionError
:
对于常见的情况,您需要抛出一个异常来响应一些意外的条件,并且您从来没有打算捕获这些异常,但是如果发生的话,您只需快速地失败以使您能够在其中调试—最符合逻辑的情况似乎是AssertionError:
if 0 < distance <= RADIUS:
#Do something.
elif RADIUS < distance:
#Do something.
else:
raise AssertionError("Unexpected value of 'distance'!", distance)
#4
16
In Python3 there are 4 different syntaxes for rasing exceptions:
在Python3中有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。提高异常(args)
If you use raise exception (args)
to raise an exception then the args
will be printed when you print the exception object - as shown in the example below.
如果您使用raise exception (args)引发异常,那么当您打印异常对象时,将会打印出args——如下面的示例所示。
#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
3.提高
raise
statement without any arguments re-raises the last exception. This is useful if you need to perform some actions after catching the exception and then want to re-raise it. But if there was no exception before, raise
statement raises TypeError
Exception.
不带任何参数的raise语句重新引发最后一个异常。如果您需要在捕获异常之后执行一些操作,然后希望重新引发异常,那么这将非常有用。但如果之前没有异常,raise语句引发TypeError异常。
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
4所示。从original_exception引发异常(args)
This statement is used to create exception chaining in which an exception that is raised in response to another exception can contain the details of the original exception - as shown in the example below.
此语句用于创建异常链接,在该链接中,为响应另一个异常而引发的异常可以包含原始异常的细节—如下面的示例所示。
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__)
Output:
输出:
ZeroDivisionError -- division by zero
MyException Zero Division
division by zero
#5
4
Read the existing answers first, this is just an addendum.
先阅读现有的答案,这只是一个附录。
Notice that you can raise exceptions with or without arguments.
注意,您可以提出带或不带参数的异常。
Example:
例子:
raise SystemExit
exits the program but you might want to know what happened.So you can use this.
退出程序,但是您可能想知道发生了什么。你可以用这个。
raise SystemExit("program exited")
this will print "program exited" to stderr before closing the program.
在关闭程序之前,这将打印“程序退出”到stderr。
#1
1784
How do I manually throw/raise an exception in Python?
Use the most specific Exception constructor that semantically fits your issue.
使用语义上适合您的问题的最特定的异常构造函数。
Be specific in your message, e.g.:
在你的信息中要具体,例如:
raise ValueError('A very specific bad thing happened.')
Don't raise generic exceptions
Avoid raising a generic Exception. To catch it, you'll have to catch all other more specific exceptions that subclass it.
避免引发通用异常。要捕获它,您必须捕获所有其他更具体的子类。
Problem 1: Hiding bugs
raise Exception('I know Python!') # Don't! If you catch, likely to hide bugs.
For example:
例如:
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',)
Problem 2: Won't catch
and more specific catches won't catch the general exception:
更具体的渔获量不会捕获一般的例外:
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
Best Practices: raise
statement
Instead, use the most specific Exception constructor that semantically fits your issue.
相反,使用语义上适合您的问题的最特定的异常构造函数。
raise ValueError('A very specific bad thing happened')
which also handily allows an arbitrary number of arguments to be passed to the constructor:
它也方便地允许任意数量的参数传递给构造函数:
raise ValueError('A very specific bad thing happened', 'foo', 'bar', 'baz')
These arguments are accessed by the args
attribute on the Exception object. For example:
这些参数由异常对象上的args属性访问。例如:
try:
some_code_that_may_raise_our_value_error()
except ValueError as err:
print(err.args)
prints
打印
('message', 'foo', 'bar', 'baz')
In Python 2.5, an actual message
attribute was added to BaseException in favor of encouraging users to subclass Exceptions and stop using args
, but the introduction of message
and the original deprecation of args has been retracted.
在Python 2.5中,一个实际的消息属性被添加到BaseException,支持鼓励用户对异常进行子类化,并停止使用args,但是消息的引入和args的原始弃用已经被撤销。
Best Practices: except
clause
When inside an except clause, you might want to, for example, log that a specific type of error happened, and then re-raise. The best way to do this while preserving the stack trace is to use a bare raise statement. For example:
当在一个except子句中时,您可能希望,例如,记录某个特定类型的错误发生,然后重新引发。保存堆栈跟踪的最佳方法是使用一个简单的raise语句。例如:
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!
Don't modify your errors... but if you insist.
You can preserve the stacktrace (and error value) with sys.exc_info()
, but this is way more error prone and has compatibility problems between Python 2 and 3, prefer to use a bare raise
to re-raise.
您可以使用sys.exc_info()来保存stacktrace(和错误值),但是这更容易出错,并且在Python 2和3之间存在兼容性问题,更倾向于使用简单的raise来重新提高。
To explain - the sys.exc_info()
returns the type, value, and traceback.
要解释——sys.exc_info()返回类型、值和回溯。
type, value, traceback = sys.exc_info()
This is the syntax in Python 2 - note this is not compatible with Python 3:
这是Python 2中的语法-注意,这与Python 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]
If you want to, you can modify what happens with your new raise - e.g. setting new args for the instance:
如果你想的话,你可以修改你的加薪计划——例如为这个例子设置新的args:
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
And we have preserved the whole traceback while modifying the args. Note that this is not a best practice and it is invalid syntax in Python 3 (making keeping compatibility much harder to work around).
我们在修改args时保留了整个回溯。注意,这不是最佳实践,而且在Python 3中是无效语法(使保持兼容性更加困难)。
>>> 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>
In Python 3:
在Python 3:
raise error.with_traceback(sys.exc_info()[2])
Again: avoid manually manipulating tracebacks. It's less efficient and more error prone. And if you're using threading and sys.exc_info
you may even get the wrong traceback (especially if you're using exception handling for control flow - which I'd personally tend to avoid.)
同样:避免手动操作回溯。它的效率更低,更容易出错。如果你使用的是线程和系统。您甚至可能会得到错误的回溯(特别是如果您在控制流中使用异常处理——我个人倾向于避免这种情况)。
Python 3, Exception chaining
In Python 3, you can chain Exceptions, which preserve tracebacks:
在Python 3中,可以对异常进行链式处理,这样可以保留回溯:
raise RuntimeError('specific message') from error
Be aware:
请注意:
- this does allow changing the error type raised, and
- 这确实允许更改引发的错误类型,并且
- this is not compatible with Python 2.
- 这与Python 2不兼容。
Deprecated Methods:
These can easily hide and even get into production code. You want to raise an exception, and doing them will raise an exception, but not the one intended!
它们可以很容易地隐藏,甚至进入生产代码。您想要引发一个异常,这样做将引发一个异常,但不是预期的异常!
Valid in Python 2, but not in Python 3 is the following:
在Python 2中有效,但在Python 3中无效的是:
raise ValueError, 'message' # Don't do this, it's deprecated!
Only valid in much older versions of Python (2.4 and lower), you may still see people raising strings:
只有在更老版本的Python(2.4和更低版本)中才有效,您仍然可以看到人们在提高字符串:
raise 'message' # really really wrong. don't do this.
In all modern versions, this will actually raise a TypeError, because you're not raising a BaseException type. If you're not checking for the right exception and don't have a reviewer that's aware of the issue, it could get into production.
在所有现代版本中,这实际上会引发一个TypeError,因为您没有引发一个BaseException类型。如果您没有检查正确的异常,并且没有意识到这个问题的检查器,那么它可以进入产品。
Example Usage
I raise Exceptions to warn consumers of my API if they're using it incorrectly:
如果用户使用我的API不正确,我就提出异常警告:
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)))
Create your own error types when apropos
"I want to make an error on purpose, so that it would go into the except"
"我想故意犯一个错误,这样它就会进入"
You can create your own error types, if you want to indicate something specific is wrong with your application, just subclass the appropriate point in the exception hierarchy:
您可以创建自己的错误类型,如果您想指示您的应用程序有什么特定的错误,只需将异常层次结构中的适当点子类化:
class MyAppLookupError(LookupError):
'''raise this when there's a lookup error for my app'''
and usage:
和用法:
if important_key not in resource_dict and not ok_to_be_missing:
raise MyAppLookupError('resource is missing, and that is not ok.')
#2
540
DON'T DO THIS. Raising a bare
Exception
is absolutely not the right thing to do; see Aaron Hall's excellent answer instead.不要这样做。提出一个纯粹的例外绝对不是正确的做法;看看艾伦·霍尔的精彩回答。
Can't get much more pythonic than this:
不能得到比这个更大的python:
raise Exception("I know python!")
See the raise statement docs for python if you'd like more info.
如果您想了解更多信息,请参阅python的raise语句文档。
#3
27
For the common case where you need to throw an exception in response to some unexpected conditions, and that you never intend to catch, but simply to fail fast to enable you to debug from there if it ever happens — the most logical one seems to be AssertionError
:
对于常见的情况,您需要抛出一个异常来响应一些意外的条件,并且您从来没有打算捕获这些异常,但是如果发生的话,您只需快速地失败以使您能够在其中调试—最符合逻辑的情况似乎是AssertionError:
if 0 < distance <= RADIUS:
#Do something.
elif RADIUS < distance:
#Do something.
else:
raise AssertionError("Unexpected value of 'distance'!", distance)
#4
16
In Python3 there are 4 different syntaxes for rasing exceptions:
在Python3中有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。提高异常(args)
If you use raise exception (args)
to raise an exception then the args
will be printed when you print the exception object - as shown in the example below.
如果您使用raise exception (args)引发异常,那么当您打印异常对象时,将会打印出args——如下面的示例所示。
#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
3.提高
raise
statement without any arguments re-raises the last exception. This is useful if you need to perform some actions after catching the exception and then want to re-raise it. But if there was no exception before, raise
statement raises TypeError
Exception.
不带任何参数的raise语句重新引发最后一个异常。如果您需要在捕获异常之后执行一些操作,然后希望重新引发异常,那么这将非常有用。但如果之前没有异常,raise语句引发TypeError异常。
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
4所示。从original_exception引发异常(args)
This statement is used to create exception chaining in which an exception that is raised in response to another exception can contain the details of the original exception - as shown in the example below.
此语句用于创建异常链接,在该链接中,为响应另一个异常而引发的异常可以包含原始异常的细节—如下面的示例所示。
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__)
Output:
输出:
ZeroDivisionError -- division by zero
MyException Zero Division
division by zero
#5
4
Read the existing answers first, this is just an addendum.
先阅读现有的答案,这只是一个附录。
Notice that you can raise exceptions with or without arguments.
注意,您可以提出带或不带参数的异常。
Example:
例子:
raise SystemExit
exits the program but you might want to know what happened.So you can use this.
退出程序,但是您可能想知道发生了什么。你可以用这个。
raise SystemExit("program exited")
this will print "program exited" to stderr before closing the program.
在关闭程序之前,这将打印“程序退出”到stderr。