で始まるループがありますfor i in range(0, 100)
。通常は正常に動作しますが、ネットワークの状態により失敗することがあります。現在、失敗continue
した場合にexcept節になるように設定しています( の次の番号に進みi
ます)。
同じ番号を に再割り当てしi
て、失敗したループの反復をもう一度実行することはできますか?
で始まるループがありますfor i in range(0, 100)
。通常は正常に動作しますが、ネットワークの状態により失敗することがあります。現在、失敗continue
した場合にexcept節になるように設定しています( の次の番号に進みi
ます)。
同じ番号を に再割り当てしi
て、失敗したループの反復をもう一度実行することはできますか?
while True
for ループ内で実行し、try
コードを内部に配置while
し、コードが成功した場合にのみそのループから抜け出します。
for i in range(0,100):
while True:
try:
# do stuff
except SomeSpecificException:
continue
break
再試行の回数を制限することを好みます。そのため、その特定のアイテムに問題がある場合、最終的に次のアイテムに進むことができます。
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.
retrying
:tenacity
およびbackoff
(2020 年更新)の代替ライブラリの再試行は以前の方法でしたが、残念ながらいくつかのバグがあり、2016 年以降更新されていません。これを書いている間、テナシティにはより多くの GItHub スター (2.3k 対 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# 3 Error occured. Retrying.
Run# 5 Error occured. Retrying.
Run# 6 Error occured. Retrying.
Run# 6 Error occured. Retrying.
Run# 10 Error occured. Retrying.
.
.
.
のその他の設定は、 tenacity GitHub ページtenacity.retry
にリストされています。
これらのい while ループを使用しない、より「機能的な」アプローチ:
def tryAgain(retries=0):
if retries > 10: return
try:
# Do stuff
except:
retries+=1
tryAgain(retries)
tryAgain()
最も明確な方法は、明示的に設定することi
です。例えば:
i = 0
while i < 100:
i += 1
try:
# do stuff
except MyException:
continue
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
私のバージョンは上記のいくつかに似ていますが、個別のwhile
ループを使用せず、すべての再試行が失敗した場合に最新の例外を再発生させます。一番上に明示的に設定できますが、エラーが発生して設定された場合にのみ最後のブロックerr = None
を実行する必要があるため、厳密には必要ありません。else
err
再帰の使用
for i in range(100):
def do():
try:
## Network related scripts
except SpecificException as ex:
do()
do() ## invoke do() whenever required inside this loop
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
Python Decorator Libraryにも似たようなものがあります。
例外をテストするのではなく、戻り値をテストすることに注意してください。装飾された関数が True を返すまで再試行します。
わずかに変更されたバージョンでうまくいくはずです。
try 句が成功した場合にのみ、ループ変数をインクリメントします