|
如何在 Python 以后可以通过except块捕获它?" M& @1 y1 b/ ~$ l3 W r
I$ [* g5 G' } 解决方案:
; [& H! ~% b# C% B" T+ [ 如何在 Python 手动抛出/引起异常?最具体的 使用语义上适合您的问题Exception 构造函数。5 Z8 _( w1 i% ^ [* j+ G
例如:
' D* a$ U, w1 ~% D( draise ValueError('A very specific bad thing happened.'), r- O2 }8 ]1 _! @8 F
不要引起一般异常避免提出泛型Exception. 要捕获它,你必须捕获所有其他子类化的异常。
/ R! `! R) F Z# q- p问题 1:隐藏错误raise Exception('I know Python!') # Don't! If you catch,likely to hide bugs.
$ v' l& v( { Z, k% y9 k& a 例如:+ U# [/ w1 t8 T' H9 X
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',)
1 ^% m) A/ y+ ] 问题2:抓不到更具体的捕获不会捕获一般异常:+ b3 s q& e6 g7 N! s/ l$ ]1 a
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 "",line 1,in File "",line 3,in demo_no_catchException: general exceptions not caught by specific handling
$ z3 I9 [8 g) L9 J0 k* z$ b" g 最佳实践:raise声明相反,请使用最具体的 Exception 结构函数。5 F& |; W, ~ V& s# {# _
raise ValueError('A very specific bad thing happened')5 U7 @& |, K' ` X
这也方便地允许将任何数量的参数传递给构造函数:( r; g g) B% ~$ U0 ~* g/ R2 Y
raise ValueError('A very specific bad thing happened','foo','bar','baz') + p, n6 \( p9 j0 @0 E
这些参数是对象的args属性访问Exception。例如:
3 f* ?3 e8 B3 ^! m, f/ E. p% Ptry: some_code_that_may_raise_our_value_error()except ValueError as err: print(err.args); D' o8 K* F9 B* k9 e& }, S
印刷+ r' q. V8 N) {
5 q! c' Q9 R4 O7 E1 S3 x$ @, f
- ('message','foo','bar','baz code]在 Python 2.在5 中,添加了实际情况message属性,以BaseException鼓励用户 Exceptions 子类化并停止使用args,但args的引入message最初的弃用已被撤回。
- h' w8 l3 ~% `: q& Q/ B7 K7 o4 K N - 最佳实践:except条款例如,当在 except 在句子中,您可能希望记录特定类型的错误,然后再次触发。保留堆栈跟踪的最佳方法是使用裸 raise 语句。[code]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!
: b; t# R1 p3 }$ M' L 不要修改你的错误......但如果你坚持的话。您可以使用 保留堆栈跟踪(和错误值)sys.exc_info(),但这更容易出错并且在 Python 2 和 3 之间存在兼容性问题,更喜欢裸体raise重新引发。9 O1 n1 g& a9 g; o, E
解释一下 -sys.exc_info()返回类型、值和追溯。* k% @& Z6 I0 q& r
type,value,traceback = sys.exc_info()
3 @- H4 ^ [+ S. S, U 这是 Python 2 语法 - 请注意,这和 Python 3 不兼容:- L) k0 E6 V1 \- w) e. t
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]
, P+ ]+ [* o4 H5 `7 c7 P& w 如果你愿意,你可以修改你的新加薪会发生什么- 例如args设置新的例子:
! t# M/ v9 |6 idef 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 )raise error_type,error_instance,traceback
' V# G$ X Q! z( R$ j- W) x1 ? 我们正在修改 args 保留了整个回溯。请注意,这个不是最好的练习,并且在 Python 3 中是无效的语法(更难保持兼容性)。
; j+ ^+ v0 z2 @8 G. a>>> catch_error_modify_message()Traceback (most recent call last): File "",line 1,in File "",line 3,in catch_error_modify_message File "",line 2,in errorValueError: oops! 5 q$ q) R7 \ k3 Q4 @5 q
在Python 3中:* ^# I" S- _' f
( V1 B X, o$ o$ l1 |! C# K- raise error.with_traceback(sys.exc_info()[2]code]第三:避免手动操作可追溯性。它的效率较低,更容易出错。若使用线程,sys.exc_info你甚至可能会得到错误的回溯(尤其是如果你处理控制流异常——我个人倾向于避免这种情况。
. s) p+ {$ k8 a R$ m# n - Python 3,链接异常在 Python 3 中,您可以链接异常,以保留可追溯性:[code]raise RuntimeError('specific message') from error0 l8 h; @4 T, M( S2 n) @
意识到:
- K1 M9 C! d& Z6 O8 n这确实允许改变引起的错误类型和& L. i1 I/ }0 V
这与 Python 2不兼容。不推荐使用方法:这些可以很容易地隐藏甚至进入生产代码。你想引起异常,这样做会引起异常,但不是预期的!0 c! v0 J1 Z! p
在 Python 2 有效,但在 Python 3无效如下:7 ~/ z: ^( t& I* k" m0 V3 U, I( t2 a
raise ValueError,'message' # Don't do this,it's deprecated!
z! i4 o7 f, R$ d! A4 T 只有更旧版本Python(2.在4 和更低的版本中,你仍然可以看到人们提出字符串:
5 ^% `0 e& J" m% Y0 P8 traise 'message' # really really wrong. don't do this.: ^, @2 M" T3 n' q- B# ^4 g
在所有现代版本中,这实际上会导致 a TypeError,因为你没有BaseException类型。如果你没有检查正确的异常并意识到这个问题,它可能会投入生产。0 K( V6 Z7 {) }& u# j* k) B% A
示例用法如果他们使用不当,我会引起异常警告消费者我的 API:
2 g- F8 O$ ~, Q& L* ^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)))" [3 o7 |( ]0 j8 z% R0 J2 p
在适当的时候创建自己的错误类型我想故意犯错误,这样它就会变成例外。
7 L4 l3 `% J% O; ~如果你想指出你的应用程序有特定的错误,你可以创建自己的错误类型,只需要适当的子类化异常层次结构:; z" u3 S9 c' f
class MyAppLookupError(LookupError): raise this when there's a lookup error for my app'''
9 G$ }9 p4 j8 \' g3 b% r8 O5 F! b. O 和用法:
o7 L+ q* H$ |4 r8 N( s" Qif important_key not in resource_dict and not ok_to_be_missing: raise MyAppLookupError('resource is missing,and that is not ok.')
! M6 M3 `6 V0 J/ x. o |
|