Pythonの優雅な再試行
2608 ワード
符号化では、ネットワーク接続に関連するいくつかのコードフラグメントが再試行されることがしばしばあり、優雅な
オリジナルバージョン
偶発的なネットワーク接続の失敗を避けるためには、再試行メカニズムを加える必要があります.最も簡単な形式は、対応するコードフラグメントにループを追加することです.ループ体に異常キャプチャを使用し、接続に成功したときにループを終了します.そうしないと、関連論理を繰り返し実行します.この場合、修正された関数
装飾品バージョン
パラメータ付き装飾品バージョン
アクセラレータがパラメータをサポートした後、必要に応じてより豊富なパラメータを定義することができます.たとえば、パラメータによってどの異常をキャプチャする必要があるかなどを設定します.
retry
装飾器およびtenacity
ライブラリの使用を一歩一歩実現する方法について説明した.オリジナルバージョン
v0.0
次のような関数形式がある場合、関数にはネットワーク接続を確立する論理があります.def f():
# do some connections
return 0
偶発的なネットワーク接続の失敗を避けるためには、再試行メカニズムを加える必要があります.最も簡単な形式は、対応するコードフラグメントにループを追加することです.ループ体に異常キャプチャを使用し、接続に成功したときにループを終了します.そうしないと、関連論理を繰り返し実行します.この場合、修正された関数
f
は次のようになります.def f():
while 1:
try:
# do some connections
break
except ConnectionError:
continue
return 0
装飾品バージョン
v1.0
アクセサリーを使用してコードを抽象化できます.例えば、現在2つの関数f1
とf2
が再試行機構を加えて、retry
という装飾器関数を書き、f1
とf2
を装飾すればよい.これにより,古いコードの修正が回避され,コード多重化も実現される.例は次のとおりです.def retry(f):
def wrap(*args, **kwargs):
while 1:
try:
return f(*args, **kwargs)
except ConnectionError:
continue
return wrap
@retry()
def f1():
# do some connections
return 0
@retry()
def f2():
# do some other connections
return 0
パラメータ付き装飾品バージョン
v1.1
v1.0
のバージョンretry
の装飾器にはいくつかの問題があります.もしある関数が3回再試行したい場合、ある関数が5回再試行したい場合、再試行の間隔も関数によって異なり、v1.0
は実現できません.この場合、パラメータ付きの3層装飾器、例えば以下のコードで実現できるretry
装飾器を用いて、times
とinterval
の2つのパラメータを入力して再試行回数と再試行間隔を設定することができるdef retry(times, interval):
def decorator(f)
def wrap(*args, **kwargs):
while times:
try:
return f(*args, **kwargs)
except ConnectionError:
times -= 1
time.sleep(interval)
continue
return wrap
return decorator
# 3 10
@retry(times=3, interval=10)
def f1():
# do some connections
return 0
# 5 15
@retry(times=5, interval=15)
def f2():
# do some other connections
return 0
アクセラレータがパラメータをサポートした後、必要に応じてより豊富なパラメータを定義することができます.たとえば、パラメータによってどの異常をキャプチャする必要があるかなどを設定します.
tenacity
リリースtenacity
はサードパーティのオープンソースライブラリで、関数の再試行に使用されています.実際には、その機能は原理と同じです.ただ定義可能なパラメータはもっと豊富で、車輪を繰り返したくなければ、直接使えばいいです.コードの例は次のとおりです.from tenacity import retry, stop_after_attempt, wait_fixed
#
@retry
def f():
# do some connections
return 0
# 5 15
@retry(stop=stop_after_attempt(5), wait=wait_fixed(15))
def f():
# do some connections
return 0