陷阱异常,请重试Python中的decorator
我对Python中的decorator没有什么经验,但我想编写一个函数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() 我想这类事情对装
@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参数委托给一些不好的方法。我保留了这些并发症:)接受解释