是否有更清洁或更pythonic的方法来执行以下操作?
try:
error_prone_function(arg1)
except MyError:
try:
error_prone_function(arg2)
except MyError:
try:
another_error_prone_function(arg3)
except MyError:
try:
last_error_prone_function(arg4)
except MyError:
raise MyError("All backup parameters failed.")
基本上它是:如果尝试#1失败,请尝试#2。如果#2失败,请尝试#3。如果#3失败,请尝试#4。如果#4失败,......如果#n失败,那么最后会引发一些异常。
请注意,我不一定每次都调用相同的函数,也不是每次都使用相同的函数参数。我上午,期望每个函数都有相同的异常MyError
。
答案 0 :(得分:10)
感谢John Kugelman的帖子here,我决定使用这个,利用for循环的鲜为人知的else
子句来执行代码,当整个列表已经用完而没有{{ 1}}发生。
break
正如Daniel Roseman在下面评论的那样,请注意缩进,因为funcs_and_args = [(func1, "150mm"),
(func1, "100mm",
(func2, "50mm"),
(func3, "50mm"),
]
for func, arg in funcs_and_args :
try:
func(arg)
# exit the loop on success
break
except MyError:
# repeat the loop on failure
continue
else:
# List exhausted without break, so there must have always been an Error
raise MyError("Error text")
语句也有try
条款。
答案 1 :(得分:2)
基于生成器的方法可能比数据驱动方法更灵活:
def attempts_generator():
# try:
# <the code you're attempting to run>
# except Exception as e:
# # failure
# yield e.message
# else:
# # success
# return
try:
print 'Attempt 1'
raise Exception('Failed attempt 1')
except Exception as e:
yield e.message
else:
return
try:
print 'Attempt 2'
# raise Exception('Failed attempt 2')
except Exception as e:
yield e.message
else:
return
try:
print 'Attempt 3'
raise Exception('Failed attempt 3')
except Exception as e:
yield e.message
else:
return
try:
print 'Attempt 4'
raise Exception('Failed attempt 4')
except Exception as e:
yield e.message
else:
return
raise Exception('All attempts failed!')
attempts = attempts_generator()
for attempt in attempts:
print attempt + ', retrying...'
print 'All good!'
我们的想法是构建一个通过重试循环逐步执行尝试块的生成器。
一旦生成器成功尝试,它将使用硬return
停止自己的迭代。不成功的尝试会产生下一个回退的重试循环。否则,如果它用尽了,它最终会抛出一个无法恢复的错误。
这里的优点是try..excepts的内容可以是你想要的任何内容,而不仅仅是单个函数调用,如果由于某种原因它特别尴尬。生成器函数也可以在闭包中定义。
正如我在这里所做的那样,收益率也可以传回日志信息。
输出上面,顺便说一句,注意我让尝试2成功写成:
mbp:scratch geo$ python ./fallback.py
Attempt 1
Failed attempt 1, retrying...
Attempt 2
All good!
如果您取消注释尝试2中的加注,那么它们都会失败,您会得到:
mbp:scratch geo$ python ./fallback.py
Attempt 1
Failed attempt 1, retrying...
Attempt 2
Failed attempt 2, retrying...
Attempt 3
Failed attempt 3, retrying...
Attempt 4
Failed attempt 4, retrying...
Traceback (most recent call last):
File "./fallback.py", line 47, in <module>
for attempt in attempts:
File "./fallback.py", line 44, in attempts_generator
raise Exception('All attempts failed!')
Exception: All attempts failed!
编辑:
就您的伪代码而言,这看起来像:
def attempts_generator():
try:
error_prone_function(arg1)
except MyError
yield
else:
return
try:
error_prone_function(arg2)
except MyError
yield
else:
return
try:
another_error_prone_function(arg3)
except MyError:
yield
else:
return
try:
last_error_prone_function(arg4)
except MyError:
yield
else:
return
raise MyError("All backup parameters failed.")
attempts = attempts_generator()
for attempt in attempts:
pass
它会让任何异常,但MyError冒出来并停止整个事情。您还可以选择为每个块捕获不同的错误。