Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/364.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
陷阱异常,请重试Python中的decorator_Python_Exception_Decorator_Python Decorators - Fatal编程技术网

陷阱异常,请重试Python中的decorator

陷阱异常,请重试Python中的decorator,python,exception,decorator,python-decorators,Python,Exception,Decorator,Python Decorators,我对Python中的decorator没有什么经验,但我想编写一个函数decorator来运行函数,捕捉特定的异常,如果捕捉到异常,则重新尝试函数一定次数。也就是说,我想这样做: @retry_if_exception(BadStatusLine, max_retries=2) def thing_that_sometimes_fails(self, foo): foo.do_something_that_sometimes_raises_BadStatusLine() 我想这类事情对装

我对Python中的decorator没有什么经验,但我想编写一个函数decorator来运行函数,捕捉特定的异常,如果捕捉到异常,则重新尝试函数一定次数。也就是说,我想这样做:

@retry_if_exception(BadStatusLine, max_retries=2)
def thing_that_sometimes_fails(self, foo):
   foo.do_something_that_sometimes_raises_BadStatusLine()
我想这类事情对装饰师来说很容易,但我不清楚具体怎么做

from functools import wraps
def retry_if_exception(ex, max_retries):
    def outer(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            assert max_retries > 0
            x = max_retries
            while x:
                try:
                    return func(*args, **kwargs)
                except ex:
                    x -= 1
        return wrapper
    return outer

看看为什么

我想你基本上想要这样的东西:

def retry_if_exception(exception_type=Exception, max_retries=1):
    def decorator(fn):
        def wrapper(*args, **kwargs):
            for i in range(max_retries+1):
                print('Try #', i+1)
                try:
                    return fn(*args, **kwargs)
                except exception_type as e:
                    print('wrapper exception:', i+1, e)
        return wrapper
    return decorator

@retry_if_exception()
def foo1():
    raise Exception('foo1')

@retry_if_exception(ArithmeticError)
def foo2():
    x=1/0

@retry_if_exception(Exception, 2)
def foo3():
    raise Exception('foo3')

如大纲所示,您将按照以下思路进行操作:

import random

def shaky():
    1/random.randint(0,1)

def retry_if_exception(f):
    def inner(retries=2):
        for retry in range(retries):
            try:
                return f()
            except ZeroDivisionError:
                print 'try {}'.format(retry)
        raise         

    return inner            

@retry_if_exception
def thing_that_may_fail():
    shaky()

thing_that_may_fail() 
如前所述,这将失败约1/2的时间

当它确实失败时,打印:

try 0
try 1
Traceback (most recent call last):
  File "Untitled 2.py", line 23, in <module>
    thing_that_may_fail()    
  File "Untitled 2.py", line 10, in inner
    return f()
  File "Untitled 2.py", line 21, in thing_that_may_fail
    shaky()
  File "Untitled 2.py", line 4, in shaky
    1/random.randint(0,1)
ZeroDivisionError: integer division or modulo by zero
尝试0
试试1
回溯(最近一次呼叫最后一次):
文件“Untitled 2.py”,第23行,在
可能失败的事情
文件“Untitled 2.py”,第10行,内部
返回f()
文件“Untitled 2.py”,第21行,在可能失败的东西中
摇摇晃晃
文件“Untitled 2.py”,第4行,格式不稳定
1/random.randint(0,1)
ZeroDivisionError:整数除法或模零除法

您可以调整此结构以适应许多不同类型的错误

以下内容似乎与您所描述的相同:

def retry_if_exception( exception, max_retries=2 ):
    def _retry_if_exception( method_fn ):
        # method_fn is the function that gives rise
        # to the method that you've decorated,
        # with signature (slf, foo)
        from functools import wraps
        def method_deco( slf, foo ):
            tries = 0
            while True:
                try:
                    return method_fn(slf, foo)
                except exception:
                    tries += 1
                    if tries > max_retries:
                        raise
        return wraps(method_fn)(method_deco)
    return _retry_if_exception
下面是一个正在使用的示例:

d = {}

class Foo():
    def usually_raise_KeyError(self):
        print("d[17] = %s" % d[17])

foo1 = Foo()

class A():
    @retry_if_exception(KeyError, max_retries=2)
    def something_that_sometimes_fails( self, foo ):
        print("About to call foo.usually_raise_KeyError()")
        foo.usually_raise_KeyError()

a = A()
a.something_that_sometimes_fails(foo1)
这使得:

About to call foo.usually_raise_KeyError()
About to call foo.usually_raise_KeyError()
About to call foo.usually_raise_KeyError()
Traceback (most recent call last):
  File " ......... TrapRetryDeco.py", line 39, in <module>
    a.something_that_sometimes_fails( foo1)
  File " ......... TrapRetryDeco.py", line 15, in method_deco
    return method_fn( slf, foo)
  File " ......... TrapRetryDeco.py", line 36, in something_that_sometimes_fails
    foo.usually_raise_KeyError()
  File " ......... TrapRetryDeco.py", line 28, in usually_raise_KeyError
    print("d[17] = %s" % d[17])
KeyError: 17
即将调用foo。通常\u raise\u KeyError()
即将调用foo。通常\u raise\u KeyError()
即将调用foo。通常\u raise\u KeyError()
回溯(最近一次呼叫最后一次):
文件“……TrapRetryDeco.py”,第39行,在
a、 有时会失败的事情(foo1)
文件“……TrapRetryDeco.py”,第15行,在方法_deco中
返回方法\u fn(slf、foo)
文件“……TrapRetryDeco.py”,第36行,有时会失败
foo.通常\u raise\u KeyError()
文件“……TrapRetryDeco.py”,第28行,通常出现错误
打印(“d[17]=%s”%d[17])
关键错误:17
我假设“2次重试”意味着操作将尝试3次。您的示例存在一些复杂情况,可能会模糊基本设置:
似乎您需要一个方法装饰器,因为您的函数/方法的第一个参数是“self”;但是,该方法会立即将其foo参数委托给一些不好的方法。我保留了这些并发症:)

接受解释