我遇到一种情况,我想在处理异常时做很多事情。由于我想就一般情况进行讨论,因此我将把我的具体情况翻译成更通用的语言。
当这段代码中有异常时,我想:
所以我可以想到两种解决方法,都很丑陋:
# Method nested-try/except block
try:
try:
do_things()
except:
rollback()
raise
except SpecificException as err:
do_advanced_logging(err)
return
# Method Duplicate Code
try:
do_things()
except SpecificException as err:
rollback()
do_advanced_logging(err)
return
except:
rollback()
raise
两者的行为相同。
我自己正在尝试嵌套的try / except解决方案。尽管速度可能会稍慢一些,但我认为速度差异在这里并不重要-至少与我的具体情况无关。我想避免重复代码,这也是因为我的rollback()语句比数据库回滚涉及的更多,即使它具有完全相同的目的(涉及到Web-API)。
还有没有发现的第三个更好的选择吗?还是重复代码方法更好?请注意,rollback()功能已被尽可能地排除,但仍包含一个函数调用和三个参数,其中包括一个硬编码的字符串。由于此字符串是唯一的,因此没有理由将其命名为常量。
答案 0 :(得分:7)
如何检查代码中的异常实例类型?
# Method .. No Duplicate Code
try:
do_things()
except Exception as e:
rollback()
if isinstance(e, SpecificException):
do_advanced_logging(e)
return
raise
答案 1 :(得分:4)
如何将回滚放在finally
子句中?像这样:
do_rollback = True
try:
do_things()
do_rollback = False
except SpecificException as err:
do_advanced_logging(err)
finally:
if do_rollback:
rollback()
一种替代方法是使用else
子句,这将使您在非异常情况下执行更多操作,并且不会将所有异常都捕获在同一位置:
do_rollback = True
try:
do_things()
except SpecificException as err:
do_advanced_logging(err)
else:
record_success()
do_rollback = False
finally:
if do_rollback:
rollback()
在record_success
可以举起SpecificException
但却不想do_advanced_logging
的情况下很有用
答案 2 :(得分:2)
您可以编写一个上下文管理器:
import random
class SpecificException(Exception):
pass
def do_things(wot=None):
print("in do_things, wot = {}".format(wot))
if wot:
raise wot("test")
def rollback():
print("rollback")
def do_advance_logging(exc_type, exc_val, traceback):
print("logging got {} ('{}')".format(exc_type, exc_val))
class rollback_on_error(object):
def __enter__(self):
return self
def __exit__(self, exc_type, exc_val, traceback):
# always rollback
rollback()
# log and swallow specific exceptions
if exc_type and issubclass(exc_type, SpecificException):
do_advance_logging(exc_type, exc_val, traceback)
return True
# propagate other exceptions
return False
def test():
try:
with rollback_on_error():
do_things(ValueError)
except Exception as e:
print("expected ValueError, got '{}'".format(type(e)))
else:
print("oops, should have caught a ValueError")
try:
with rollback_on_error():
do_things(SpecificException)
except Exception as e:
print("oops, didn't expect exception '{}' here".format(e))
else:
print("ok, no exception")
try:
with rollback_on_error():
do_things(None)
except Exception as e:
print("oops, didn't expect exception '{}' here".format(e))
else:
print("ok, no exception")
if __name__ == "__main__":
test()
但是除非您有十多次这种模式出现,否则我宁愿使用非常明显且完美的pythonic解决方案-嵌套异常处理程序或except子句中的显式类型检查(isinstance
)。