Python:尝试三次函数直到全部失败

时间:2014-08-03 16:11:21

标签: python design-patterns error-handling

我在Python 2.7写作并遇到以下情况。我想尝试三次调用函数。如果所有三次都出错,我会提出我得到的最后一个错误。如果任何一个呼叫成功,我将退出尝试并立即继续。

这就是我现在所拥有的:

output = None
error = None
for _e in range(3):
    error = None
    try:
        print 'trial %d!' % (_e + 1)
        output = trial_function()
    except Exception as e:
        error = e
    if error is None:
        break
if error is not None:
    raise error

是否有更好的代码段可以实现相同的用例?

4 个答案:

答案 0 :(得分:4)

使用装饰器

from functools import wraps

def retry(times):

    def wrapper_fn(f):

        @wraps(f)
        def new_wrapper(*args,**kwargs):
            for i in range(times):
                try:
                    print 'try %s' % (i + 1)
                    return f(*args,**kwargs)
                except Exception as e:
                    error = e
            raise error

        return new_wrapper

    return wrapper_fn

@retry(3)
def foo():
    return 1/0;

print foo()

答案 1 :(得分:3)

这是一种可能的方法:

def attempt(func, times=3):
    for _ in range(times):
        try:
            return func()
        except Exception as err:
            pass
    raise err

带有print语句的演示:

>>> attempt(lambda: 1/0)
Attempt 1
Attempt 2
Attempt 3

Traceback (most recent call last):
  File "<pyshell#18>", line 1, in <module>
    attempt(lambda: 1/0)
  File "<pyshell#17>", line 8, in attempt
    raise err
ZeroDivisionError: integer division or modulo by zero

答案 2 :(得分:1)

忽略调试输出和古老的Python方言,这看起来不错。我唯一要改变的是将它放入一个函数中,然后你可以简单地返回trial_function()的结果。此外,error = None变得不必要,包括相关的检查。如果循环终止,则必须设置错误,因此您可以抛出它。如果您不想要一个函数,可以考虑将else与for循环结合使用,并在第一个结果后使用。

for i in range(3):
    try:
        result = foo()
        break
    except Exception as error:
        pass
else:
    raise error
use_somehow(result)

当然,使用装饰器进行功能的建议仍然存在。你也可以在本地应用它,装饰器语法毕竟只是语法糖:

# retry from powerfj's answer below
rfoo = retry(3)(foo)
result = rfoo()

答案 3 :(得分:1)

遇到了一种干净的重试方式。有一个名为 retry 的模块。

  • 首先使用

    安装模块
    pip install retry
    
  • 然后在代码中导入模块。

    from retry import retry
    
  • 在方法上方使用@retry装饰器,我们可以将参数传递给装饰器。一些参数是 triesdelayException

示例

    from retry import retry

    @retry(AssertionError, tries=3, delay=2)
    def retryfunc():
        try:
            ret = False
            assert ret, "Failed"
        except Exception as ex:
            print(ex)
            raise ex
  • 上面的代码每次都断言并失败,但重试装饰器重试3 次,两次重试之间的延迟为2 秒。此外,这只会重试断言失败,因为我们已将错误类型指定为 AssertionError 函数不会重试的任何其他错误。