for i in range(0, 100)
で始まるループがあります。通常は正常に動作しますが、ネットワークの状態が原因で失敗することもあります。現在、失敗した場合にexcept節でcontinue
になるように設定しています(i
の次の番号に進みます)。
同じ番号をi
に再割り当てして、失敗したループの繰り返しを再度実行することは可能ですか?
Forループ内でwhile True
を実行し、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.
パッケージの再試行 は、失敗時にコードのブロックを再試行する良い方法です。
例えば:
@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")
他のソリューションと同様のソリューションを次に示しますが、規定の回数または再試行で成功しない場合は例外が発生します。
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
これらのい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 i in range(100):
def do():
try:
## Network related scripts
except SpecificException as ex:
do()
do() ## invoke do() whenever required inside this loop
タイムアウトのある一般的なソリューション:
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)
使用法:
for retry in onerror_retry(SomeSpecificException, do_stuff):
retry()
Python Decorator Library にも似たようなものがあります。
例外をテストするのではなく、戻り値をテストすることに注意してください。装飾された関数がTrueを返すまで再試行します。
わずかに変更されたバージョンがトリックを行うはずです。
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再試行パッケージを使用できます。 再試行中
ほぼすべてに再試行動作を追加するタスクを簡素化するために、Pythonで記述されています。
ネストされたループを使用せず、成功時にbreak
を呼び出すソリューションが必要な場合は、イテレート可能オブジェクトの簡単なラップretriable
を開発できます。よくあるネットワークの問題の例を次に示します-保存された認証の有効期限が切れます。使用方法は次のようになります。
client = get_client()
smart_loop = retriable(list_of_values):
for value in smart_loop:
try:
client.do_something_with(value)
except ClientAuthExpired:
client = get_client()
smart_loop.retry()
continue
except NetworkTimeout:
smart_loop.retry()
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(0, 10):
try:
#things I need to do
except ValueError:
print("Try #{} failed with ValueError: Sleeping for 2 secs before next try:".format(i))
time.sleep(2)
continue
break