web-dev-qa-db-ja.com

例外後に再試行する方法は?

for i in range(0, 100)で始まるループがあります。通常は正常に動作しますが、ネットワークの状態が原因で失敗することもあります。現在、失敗した場合にexcept節でcontinueになるように設定しています(iの次の番号に進みます)。

同じ番号をiに再割り当てして、失敗したループの繰り返しを再度実行することは可能ですか?

196
FurtiveFelon

Forループ内でwhile Trueを実行し、tryコードを内部に配置し、コードが成功した場合にのみwhileループを中断します。

for i in range(0,100):
    while True:
        try:
            # do stuff
        except SomeSpecificException:
            continue
        break
303
zneak

再試行の回数を制限して、その特定のアイテムに問題がある場合、最終的に次のアイテムに進むようにします。

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.
150
xorsyst

パッケージの再試行 は、失敗時にコードのブロックを再試行する良い方法です。

例えば:

@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")
55
goneri

他のソリューションと同様のソリューションを次に示しますが、規定の回数または再試行で成功しない場合は例外が発生します。

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
16
TheHerk

これらのいwhileループを使用しない、より「機能的な」アプローチ:

def tryAgain(retries=0):
    if retries > 10: return
    try:
        # Do stuff
    except:
        retries+=1
        tryAgain(retries)

tryAgain()
14
restbeckett

最も明確な方法は、iを明示的に設定することです。例えば:

i = 0
while i < 100:
    i += 1
    try:
        # do stuff

    except MyException:
        continue
9
Tomi Kyöstilä

再帰を使用する

for i in range(100):
    def do():
        try:
            ## Network related scripts
        except SpecificException as ex:
            do()
    do() ## invoke do() whenever required inside this loop
5
Joseph Thomas

タイムアウトのある一般的なソリューション:

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()
5
Laurent LAPORTE

Python Decorator Library にも似たようなものがあります。

例外をテストするのではなく、戻り値をテストすることに注意してください。装飾された関数がTrueを返すまで再試行します。

わずかに変更されたバージョンがトリックを行うはずです。

4
Michael

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
2
Ranju R

Python再試行パッケージを使用できます。 再試行中

ほぼすべてに再試行動作を追加するタスクを簡素化するために、Pythonで記述されています。

2
ManJan

ネストされたループを使用せず、成功時に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
1
Mikhail
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ブロックを実行する必要があるため、厳密には必要ありません。

1
n8henrie

私は自分のコードで以下を使用し、

   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
0
H S Rathore