zne*_*eak 337
while True在你的for循环内部执行,将try代码放入其中,并while在代码成功时从该循环中断.
for i in range(0,100):
while True:
try:
# do stuff
except SomeSpecificException:
continue
break
Run Code Online (Sandbox Code Playgroud)
xor*_*yst 165
我倾向于限制重试次数,所以,如果有与特定项目,你最终会延续到下一个,这样一个问题:
for i in range(100):
for attempt in range(10):
try:
# do thing
except:
# perhaps reconnect, etc.
else:
break
else:
# we failed all the attempts - deal with the consequences.
Run Code Online (Sandbox Code Playgroud)
gon*_*eri 60
在重试包是重试的代码块失败的好办法.
例如:
@retry(wait_random_min=1000, wait_random_max=2000)
def wait_random_1_to_2_s():
print("Randomly wait 1 to 2 seconds between retries")
Run Code Online (Sandbox Code Playgroud)
The*_*erk 19
这是一个类似于其他解决方案的解决方案,但如果在规定的数量或重试中没有成功,它将引发异常.
tries = 3
for i in range(tries):
try:
do_the_thing()
except KeyError as e:
if i < tries - 1: # i is zero indexed
continue
else:
raise
break
Run Code Online (Sandbox Code Playgroud)
小智 15
没有使用那些丑陋的while循环的更"功能"的方法:
def tryAgain(retries=0):
if retries > 10: return
try:
# Do stuff
except:
retries+=1
tryAgain(retries)
tryAgain()
Run Code Online (Sandbox Code Playgroud)
np8*_*np8 14
retrying:tenacity和backoff(2020 年更新)将重试库是以前的路要走,但可悲的是它有一些缺陷,自2016年其他选择似乎还没有得到任何更新补偿和坚韧。在写这篇文章的时候,坚韧有更多的 GItHub 星(2.3k vs 1.2k)并且最近更新,因此我选择使用它。下面是一个例子:
from functools import partial
import random # producing random errors for this example
from tenacity import retry, stop_after_delay, wait_fixed, retry_if_exception_type
# Custom error type for this example
class CommunicationError(Exception):
pass
# Define shorthand decorator for the used settings.
retry_on_communication_error = partial(
retry,
stop=stop_after_delay(10), # max. 10 seconds wait.
wait=wait_fixed(0.4), # wait 400ms
retry=retry_if_exception_type(CommunicationError),
)()
@retry_on_communication_error
def do_something_unreliable(i):
if random.randint(1, 5) == 3:
print('Run#', i, 'Error occured. Retrying.')
raise CommunicationError()
for i in range(100):
do_something_unreliable(i)
Run Code Online (Sandbox Code Playgroud)
上面的代码输出如下:
Run# 3 Error occured. Retrying.
Run# 5 Error occured. Retrying.
Run# 6 Error occured. Retrying.
Run# 6 Error occured. Retrying.
Run# 10 Error occured. Retrying.
.
.
.
Run Code Online (Sandbox Code Playgroud)
更多设置tenacity.retry在tenacity GitHub 页面上列出。
最明确的方法是明确设置i.例如:
i = 0
while i < 100:
i += 1
try:
# do stuff
except MyException:
continue
Run Code Online (Sandbox Code Playgroud)
for _ in range(5):
try:
# replace this with something that may fail
raise ValueError("foo")
# replace Exception with a more specific exception
except Exception as e:
err = e
continue
# no exception, continue remainder of code
else:
break
# did not break the for loop, therefore all attempts
# raised an exception
else:
raise err
Run Code Online (Sandbox Code Playgroud)
我的版本与以上几个类似,但不使用单独的while循环,如果所有重试都失败,则会重新引发最新的异常。可以err = None在顶部显式设置,但不是绝对必要的,因为它应该只在else出现错误时才执行最后一个块,因此err被设置。
Python Decorator Library中有类似的东西。
请记住,它不测试异常,而是测试返回值。它会重试,直到修饰函数返回 True。
稍作修改的版本应该可以解决问题。
具有超时的通用解决方案:
import time
def onerror_retry(exception, callback, timeout=2, timedelta=.1):
end_time = time.time() + timeout
while True:
try:
yield callback()
break
except exception:
if time.time() > end_time:
raise
elif timedelta > 0:
time.sleep(timedelta)
Run Code Online (Sandbox Code Playgroud)
用法:
for retry in onerror_retry(SomeSpecificException, do_stuff):
retry()
Run Code Online (Sandbox Code Playgroud)
使用 while 和计数器:
count = 1
while count <= 3: # try 3 times
try:
# do_the_logic()
break
except SomeSpecificException as e:
# If trying 3rd time and still error??
# Just throw the error- we don't have anything to hide :)
if count == 3:
raise
count += 1
Run Code Online (Sandbox Code Playgroud)
使用递归
for i in range(100):
def do():
try:
## Network related scripts
except SpecificException as ex:
do()
do() ## invoke do() whenever required inside this loop
Run Code Online (Sandbox Code Playgroud)
attempts = 3
while attempts:
try:
...
...
<status ok>
break
except:
attempts -=1
else: # executed only break was not raised
<status failed>Run Code Online (Sandbox Code Playgroud)
小智 5
装饰器是一个很好的方法。
from functools import wraps
import time
class retry:
def __init__(self, success=lambda r:True, times=3, delay=1, raiseexception=True, echo=True):
self.success = success
self.times = times
self.raiseexception = raiseexception
self.echo = echo
self.delay = delay
def retry(fun, *args, success=lambda r:True, times=3, delay=1, raiseexception=True, echo=True, **kwargs):
ex = Exception(f"{fun} failed.")
r = None
for i in range(times):
if i > 0:
time.sleep(delay*2**(i-1))
try:
r = fun(*args, **kwargs)
s = success(r)
except Exception as e:
s = False
ex = e
# raise e
if not s:
continue
return r
else:
if echo:
print(f"{fun} failed.", "args:", args, kwargs, "\nresult: %s"%r)
if raiseexception:
raise ex
def __call__(self, fun):
@wraps(fun)
def wraper(*args, retry=0, **kwargs):
retry = retry if retry>0 else self.times
return self.__class__.retry(fun, *args,
success=self.success,
times=retry,
delay=self.delay,
raiseexception = self.raiseexception,
echo = self.echo,
**kwargs)
return wraper
Run Code Online (Sandbox Code Playgroud)
一些用法示例:
@retry(success=lambda x:x>3, times=4, delay=0.1)
def rf1(x=[]):
x.append(1)
print(x)
return len(x)
> rf1()
[1]
[1, 1]
[1, 1, 1]
[1, 1, 1, 1]
4
Run Code Online (Sandbox Code Playgroud)
@retry(success=lambda x:x>3, times=4, delay=0.1)
def rf2(l=[], v=1):
l.append(v)
print(l)
assert len(l)>4
return len(l)
> rf2(v=2, retry=10) #overwite times=4
[2]
[2, 2]
[2, 2, 2]
[2, 2, 2, 2]
[2, 2, 2, 2, 2]
5
Run Code Online (Sandbox Code Playgroud)
> retry.retry(lambda a,b:a+b, 1, 2, times=2)
3
Run Code Online (Sandbox Code Playgroud)
> retry.retry(lambda a,b:a+b, 1, "2", times=2)
TypeError: unsupported operand type(s) for +: 'int' and 'str'
Run Code Online (Sandbox Code Playgroud)