回答

收藏

在 Python 中手动引发(抛出)异常

技术问答 技术问答 181 人阅读 | 0 人回复 | 2023-09-12

如何在 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( d
    raise 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% P
    try:    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 i
    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     )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 t
    raise '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" Q
    if 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
分享到:
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则