我对Python中的装饰器没什么经验,但是我想编写一个运行该函数的函数装饰器,捕获一个特定的异常,如果捕获到该异常,则重新尝试该函数一定次数。也就是说,我想这样做:
@retry_if_exception(BadStatusLine, max_retries=2)
def thing_that_sometimes_fails(self, foo):
foo.do_something_that_sometimes_raises_BadStatusLine()
我认为装饰者很容易做到这一点,但我不知道如何去做。
答案 0 :(得分:2)
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
答案 1 :(得分:1)
我认为你基本上想要这样的东西:
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')
答案 2 :(得分:0)
作为概要,你可以按照以下方式做点什么:
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
您可以将此结构调整为许多不同类型的错误。
答案 3 :(得分:0)
以下似乎做了您所描述的内容:
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
我认为通过&#34; 2重试&#34;你的意思是手术将被尝试3次全部告诉。您的示例有一些复杂性可能会掩盖基本设置: 你似乎想要一个方法装饰器,因为你的函数/方法的第一个参数是&#34; self&#34 ;;但是,该方法会立即委托其foo参数的一些不良方法。我保留了这些并发症:)