API的异常分为定义异常与调用API时如何捕获异常两个部分,这二者相辅相成。
定义API异常的技巧
在自己编写API的时候,应该定义Root Exception——API中的根异常,其它异常都继承于它。这样的做法有两个好处:
API代码层次更清晰
API与调用程序代码隔离
假设存在如下场景:需要做一个链接数据库服务的模块。提供一个connect函数用于链接。那么,在链接的过程中,就会发生以下几种情况:
socket连接超时
socket拒绝连接
针对以上的情况,我们在模块中定义几个异常:
# database.py
class Error(Exception):
"""Root exception for all exceptions raised by this module."""
class SocketTimeError(Error):
pass
class SocketRefuseError(Error):
pass
def connect():
pass
调用API时异常捕获的技巧
这样在调用API的时候就可以这样使用:
try:
connect()
except SocketTimeError as err:
log.error(err)
except SocketRefuseError as err:
log.error(err)
except Error as err:
log.error("API Unexpected error:%s" % err)
except Exception:
log.error("API bug cause exception.")
这样精确定义多个异常,使得代码层次清晰,增强了可读性。值得注意的是:在代码的***还捕获了Error以及Exception两个异常,这两个操作分别对应于可拓展性与健壮性的目的。
捕获Root Exception以提高可拓展性:
我们知道,在实际链接数据库时,还可能会出现用户没有登陆权限等问题。所以,我们需要在下一个版本中加入PermissionDeny这个异常。但是,旧的调用代码已经写好了,如果忘记修改的话,这个异常可能就会无法被处理,进而使得调用的程序奔溃。处于这样的考虑,我们在调用API的时候,就应该再捕获API的Root Exception,即使之后新加入了其它的异常,在这一个except中也能被捕获而不影响调用程序。使得API模块的可拓展性得到了提高。