对异常重复Python函数调用?

对异常重复Python函数调用?,python,Python,大家好,我正在做一个数据清理项目,我正在寻找一种干净的方法,在出现异常时重复函数调用 伪代码: try: myfunc(x) except myError: ###try to call myfunc(x) again Y number of times, until success(no exceptions raised) otherwise raise myError2 我意识到这根本不是最佳实践,但我正在处理许多不同的代码/网络层,这些代码/网络层不可

大家好,我正在做一个数据清理项目,我正在寻找一种干净的方法,在出现异常时重复函数调用

伪代码:

try:
    myfunc(x)
except myError:
    ###try to call myfunc(x) again Y number of times, 
        until success(no exceptions raised) otherwise raise myError2
我意识到这根本不是最佳实践,但我正在处理许多不同的代码/网络层,这些代码/网络层不可靠,我无法实际调试它们

现在我正在用大量的试块来完成这项工作,这让我的眼睛流血

有人有什么好主意吗?

试试下面的片段:

while True:
    try:
        func()
        break
    except:
        print "Error. Gonna try again"
但最好限制重试次数。

使用循环

i = 0
while True:
  try: myfunc(x); break;
  except myError:
    i = i + 1;
    # print "Trying again"
    if i > 5: raise myError2;
success=False
尝试次数=0
而不是成功和尝试<10:#或者无论你想尝试多少次
尝试:
函数调用()
成功=正确
除:
i+=1
如果不成功:
升起功能调用失败错误

希望这有助于

准确地做你想做的事情,你可以做如下事情:

import functools
def try_x_times(x, exceptions_to_catch, exception_to_raise, fn):
    @functools.wraps(fn) #keeps name and docstring of old function
    def new_fn(*args, **kwargs):
        for i in xrange(x):
            try:
                return fn(*args, **kwargs)
            except exceptions_to_catch:
                 pass
        raise exception_to_raise
    return new_fn
然后将旧函数包装到新函数中:

#instead of
#risky_method(1,2,'x')
not_so_risky_method = try_x_times(3, (MyError,), myError2, risky_method)
not_so_risky_method(1,2,'x')

#or just
try_x_times(3, (MyError,), myError2, risky_method)(1,2,'x')

我喜欢用递归解决这些问题:

def tryfor(times, on_failure, excepts, func, *args, **kwargs):
    if times < 1:
        raise on_failure()
    try:
        return func(*args, **kwargs)
    except excepts:
        return tryfor(times-1, on_failure, excepts, func, *args, **kwargs)


tryfor(3, PermanentException, (SomeError,), dostuff,1,2)
def tryfor(次数、故障时、例外、函数、*args、**kwargs):
如果时间<1:
在失败时提出()
尝试:
返回函数(*args,**kwargs)
除例外情况外:
返回tryfor(times-1,在_失败时,例外,func,*args,**kwargs)
尝试(3,永久异常,(某些错误),dostuff,1,2)

在n次重试后照常引发异常

from functools import wraps

def retry(times):
    """
    Decorator to retry any functions 'times' times.
    """
    def retry_decorator(func):
        @wraps(func)
        def retried_function(*args, **kwargs):
            for i in range(times - 1):
                try:
                    func(*args, **kwargs)
                    return
                except Exception:  
                    pass
            func(*args, **kwargs)

        return retried_function

    return retry_decorator


# test

attempts = 3

@retry(4)
def function_that_raises_error():
    global attempts
    if 0 < attempts:
        print("fail")
        attempts -= 1
        raise Exception

    print("pass")

function_that_raises_error()
从functools导入包装
def重试次数:
"""
Decorator重试任何函数“次”次。
"""
def retry_装饰器(func):
@包装(func)
def重试_函数(*args,**kwargs):
对于范围内的i(乘以-1):
尝试:
func(*args,**kwargs)
返回
除例外情况外:
通过
func(*args,**kwargs)
返回重试函数
返回重试修饰符
#试验
尝试次数=3次
@重试(4)
def函数_引发_错误():
全球尝试
如果0<尝试次数:
打印(“失败”)
尝试次数-=1
引发异常
打印(“通行证”)
函数\u引发\u错误()

在这种情况下,goto会非常有用。@Rafe:不,它真的不会。一般来说,尤其是在网络任务中,应该使用an来找到合适的速率。立即重试可能会导致资源浪费。这个想法如图所示。请使用functools.wrapps,而不是更改_name _; yourself.Cool。实际上,我最终还是使用了它,但它的想法基本相同。
除了:
在大多数(但不是所有)情况下都不是一个好主意。我宁愿使用
,例外情况除外:
。当然,这是假设
func()
将终止。这正是我要找的。谢谢它的尾巴优化了吗?
def tryfor(times, on_failure, excepts, func, *args, **kwargs):
    if times < 1:
        raise on_failure()
    try:
        return func(*args, **kwargs)
    except excepts:
        return tryfor(times-1, on_failure, excepts, func, *args, **kwargs)


tryfor(3, PermanentException, (SomeError,), dostuff,1,2)
from functools import wraps

def retry(times):
    """
    Decorator to retry any functions 'times' times.
    """
    def retry_decorator(func):
        @wraps(func)
        def retried_function(*args, **kwargs):
            for i in range(times - 1):
                try:
                    func(*args, **kwargs)
                    return
                except Exception:  
                    pass
            func(*args, **kwargs)

        return retried_function

    return retry_decorator


# test

attempts = 3

@retry(4)
def function_that_raises_error():
    global attempts
    if 0 < attempts:
        print("fail")
        attempts -= 1
        raise Exception

    print("pass")

function_that_raises_error()