如何在python中重复异常?

时间:2014-11-07 04:58:41

标签: python python-2.7

在python中引发异常后重复某些内容的最优雅方法是什么?

我有类似的东西[伪代码作为例子]:

try:
  do_some_database_stuff()
except DatabaseTimeoutException:
  reconnect_to_database()
  do_some_database_stuff() # just do it again

但是想象一下,如果我没有一个很好的功能,而是很多代码。重复的代码不是很好。

所以我认为这稍微好一些:

while True:
  try:
    do_some_database_stuff()
    break
  except DatabaseTimeoutException:
    reconnect_to_database()

如果异常确实解决了问题,那就足够了。如果不是,我需要一个计数器来防止无限循环:

i = 0
while i < 5:
  try:
    do_some_database_stuff()
    break
  except DatabaseTimeoutException:
    reconnect_to_database()
    i += 1

但是我不知道它是否有效,所以它也是:

while i <= 5:
  try:
    do_some_database_stuff()
    break
  except DatabaseTimeoutException:
    if i != 5:
     reconnect_to_database()
    else:
      raise DatabaseTimeoutException
    i += 1

正如你所看到的,它开始变得非常混乱。

表达这种逻辑的最优雅方式是什么?

  • 尝试一下
  • 如果失败则应用修复
  • 尝试更多次,包括修复
  • 如果它继续失败,请给我一个错误以防止无限循环

2 个答案:

答案 0 :(得分:6)

您可以使用&#34; for-else&#34;循环:

for ii in range(5):
    try:
        do_some_database_stuff()
        break
    except DatabaseTimeoutException:
        reconnect_to_database()
else:
    raise DatabaseTimeoutException

或者,没有:

for ii in range(5):
    try:
        do_some_database_stuff()
        break
    except DatabaseTimeoutException:
        if ii == 4:
            raise
        reconnect_to_database()

答案 1 :(得分:1)

我个人不是for-else构造的粉丝。我不认为它是直观的。我第一次阅读它时,我认为它意味着“为循环(...)做,如果迭代是空的那么......”。

您应该将代码放在函数中。如果do_some_database_stuff()成功完成,那么您可以使用return语句从函数中提前返回。

例如

def try_to_do_some_database_stuff():
    for i in range(num_times):
        try:
            return do_some_database_stuff()
        except DatabaseTimeoutException:
            reconnect_to_database()
    raise DatabaseTimeoutException

如果您发现自己使用此构造很多,那么您可以使它更通用。

def try_to_do(func, catch, times=2, on_exception=None):
    for i in range(times):
        try:
            return func()
        except catch:
            if on_exception:
                on_exception()
    raise catch

try_to_do(do_some_database_stuff, catch=DatabaseTimeoutException, times=5, 
    on_exception=reconnect_to_database)

如果需要将参数传递给函数,可以使用functools.partial