我想执行多个函数,收集它们的异常(如果有),并引发复合异常,调用尽可能多的函数,而不会在出现异常后中断。例如,假设我有
def f():
do_one()
do_two()
do_three()
do_i
函数不依赖于彼此的状态。做我想做的事情的最明显的方法是:
def f():
errors = []
for do_i in [do_one, do_two, do_three]:
try:
do_i()
except Exception as e:
errors.append(e)
if errors:
raise Exception(';'.join(errors))
或者稍微好一点:
def catch_error(arr, f, *args, **kwargs):
try:
return f(*args, **kwargs)
except Exception as e:
arr.append(e)
return None
def f():
errors = []
for do_i in [do_one, do_two, do_three]:
catch_error(errors, do_i)
if errors:
raise Exception(';'.join(errors))
但这仍然很丑陋。有没有一种我所缺少的 Pythonic 方法可以做到这一点,也许可以巧妙地使用 with
语句?
编辑:在理想的世界中,Python 会有这样的:
errors = []
awesome_block(errors):
do_one()
do_two()
do_three()
return 'yes!' if not errors else ';'.join(map(str, errors))
最佳答案
您可以将函数重写为上下文管理器,这确实会稍微简化您的代码。我保留了传递列表的约定,尽管这会产生内部列表,以便您稍后可以使用它。
from contextlib import contextmanager
@contextmanager
def catch_errors(error_list=None):
error_list = error_list if error_list is not None else []
try:
yield error_list
except Exception as e:
error_list.append(e)
error_list = []
with catch_errors(error_list):
raise Exception("First exception")
with catch_errors(error_list):
raise ValueError("Second exception")
if error_list:
raise Exception(";".join(map(repr, error_list)))
我认为这里的repr
比str
更有用。 @contextmanager
允许在 with 语句中使用,而您只需将函数编写为生成器。
如果您没有将列表传递给生成器,那么您需要跟踪返回的列表。
with catch_errors() as errors1:
raise Exception("First exception")
print errors1 # Exception("First exception",)
关于python - Try...除了多个独立的语句外,执行尽可能多的语句,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17287849/