【发布时间】:2013-05-07 14:25:45
【问题描述】:
我正在清理一个 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)
这听起来像是确保用户只知道 Pass/Fail 的好方法,而开发人员可以维护一种支持方法吗?
更新
基于最佳实践的共识,我不会陷入困境。
最初的目标是让人们这样做:
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 时,我似乎每天都发现一个新异常。这些异常往往会变得很长且难以维护。
【问题讨论】:
-
您确定要使用这样的机制吗?你只会用你的“假”例外来掩盖一个真正的例外。我只想留下未处理的异常,因为它们是最能提供信息的。如果您想将它们记录在某处或创建一般操作,那就是另一回事了。
-
我不确定我想这样做。我担心的是有一些错误代码可能会从一个底层库中弹出。查看我自己使用这个库的“消费者”代码,我不得不将对该库的调用嵌套在它自己的块中,然后围绕它链接大量的异常处理来捕获这些错误。我正在尝试将这种异常处理移植到上游,这似乎是一种潜在的方式,可以最大限度地减少消费者的大部分工作 - 同时仍然保留异常。