其他分享
首页 > 其他分享> > 如何处理未处理的异常?

如何处理未处理的异常?

作者:互联网

我正在清理API库,并尝试找出处理未处理异常的最佳方法.

现在,该库几乎捕获了API可能出错的所有内容-凭据错误,服务器错误,urllib2错误,httplib错误等.这将存在一些极端情况.

我当前的想法是99%的库用户不关心异常本身,他们只关心API调用失败.只有开发人员才会关心该异常.

这使我想到了这个解决方案:

class ApiError(Exception):
    pass

class ApiUnhandledError(ApiError):
    pass

API的已知问题会引发ApiError或特定的子类.

其他所有内容都会引发ApiUnhandledError,并保留原始错误,用户可以捕获或忽略该错误.

try:
    stuff
except urllib2.UrlError , e :
    raise ApiError(raised=e)
except Exception as e :
    raise ApiUnhandledError(raised=e)

这听起来像是确保用户只知道通过/失败,同时开发人员可以维持支持方法的好方法吗?

更新资料

基于最佳实践的共识,我不会对此加以限制.

最初的目标是允许人们这样做:

try:
   stuff_a
   other_stuff
   even_more_stuff

   api.proxy(url)

   again_stuff
   again_others
 except api.ApiUnhandledError , e :
    handle error
 except api.ApiError , e :
    handle error
 except Stuff , e :
     other error
 except:
     raise

在该示例中,用户只需捕获ApiError(以及可选的ApiUnhandledError或任何其他子类)

我认为这将比每个具有自己的块的api交互都更可取:

try:
   stuff_a
   other_stuff
   even_more_stuff

   try:
       api.proxy(url)
     except api.ApiError , e :
        handle error
     except CatchSomething1 , e :
        handle error
     except CatchSomething2 , e :
        handle error
     except CatchSomething3 , e :
        handle error
     except CatchSomething4 , e :
        handle error
     except:
        raise

   again_stuff
   again_others
 except Stuff , e :
     other error
 except:
     raise

当处理urllib2时,我似乎每天都发现一个新的异常.这些异常往往会变得非常漫长且难以维护.

解决方法:

如果您的图书馆提出了一个您没有预见到并且您没有处理的异常,那就这样.这可能是库错误的标志,否则将被忽略.如果可以明确指出错误的原因,则可以捕获并重新启动(例如,在authenticator方法中捕获socket.error并重新启动AuthenticationFailedError),但是对库用户(谁是程序员自己).

用户不应该尝试处理或消除直接来自库内部的错误(即,不是您的API的一部分-大致上,不是您编写或提出的错误),因为它们是该代码段的内部内容.如果图书馆作者忘了处理它们或赶上并重新启动更具体的一个,那是一个错误,应该报告.如果函数对输入进行了假设(例如,针对速度),则应在API参考中明确说明,并且任何违规都是用户的错.

在Python2中,只能引发继承自BaseException的经典类或新样式类,而在Python3中,经典类已消失,因此您的库可能引发的任何事情都必须从BaseException继承.用户通常要处理的任何异常(不包括SystemExit,GeneratorExit,KeyboardInterrupt等,它们都有特殊情况)必须从Exception继承.尝试提高时会报告未这样做:

Python3:

>>> class Test:
...     pass
... 
>>> raise Test()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: exceptions must derive from BaseException

Python2:

>>> class Test(object):
...     pass
... 
>>> raise Test()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: exceptions must be old-style classes or derived from BaseException, not Test
>>> 

就是说,您不需要将异常包装在UnhandledException容器内,只需使代码中的所有异常都继承自Exception.屏蔽失败是一种不好的做法(您不应该鼓励这样做),但是懒惰的用户仍然可以利用Exception基类的继承,并使用以下方法捕获所有未处理的异常:

try:
    yourapi.call_me()
except APIKnownError as error:
    report(error)
except Exception as error:
    pass
    # Or whatever

值得注意的是,Python提供了一个warnings模块来报告“程序中的某些条件,该条件(通常)不保证引发异常并终止程序”.

说到应用程序框架(不是库),我非常喜欢Tornado方法:它将记录所有未处理的异常,如果错误不严重,则继续执行.我认为该决定应由最终用户决定.

标签:exception-handling,python
来源: https://codeday.me/bug/20191123/2066795.html