Python デコレータを使用してコード ブロックを再試行する
関数またはクラスをデコレータで変更して、関数の動作を永続的に変更することなく拡張できます。 この記事では、retry
デコレーターを使用して、既存の関数を変更せずに既存の関数を変更する方法について説明します。
この場合、変更により、戻り値が必要なものと異なる可能性がある特定の状況で、関数が数回再試行されます。
retry
デコレーターの重要性
デコレータを使用して特定の関数の動作を拡張できます。また、アクセス権がない場合や変更したくない場合でも、デコレータを簡単に作成してその関数を変更できます。
この関数はかなり特殊な方法で必要になることがよくあります。そこで Python デコレータの出番です。では、デコレータがどのように機能するかを示す簡単な関数を作成しましょう。
単純な関数 quotient()
は 2つの引数を取り、最初の引数を 2 番目の引数で割ります。
def quotient(a, b):
return a / b
print(quotient(3, 7))
出力:
0.42857142857142855
ただし、除算の結果を常に大きい方が除算されるようにしたい場合 (したがって、結果は 2.3333333333333335
になります)、コードを変更するか、decorators
を使用することができます。
デコレータを使用すると、コード ブロックを変更せずに関数の動作を拡張できます。
def improv(func):
def inner(a, b):
if a < b:
a, b = b, a
return func(a, b)
return inner
@improv
def quotient(a, b):
return a / b
print(quotient(3, 7))
出力:
2.3333333333333335
improv()
関数は、quotient()
関数を引数として取り、quotient()
関数の引数を取り、必要な追加機能をもたらす内部関数を保持するデコレーター関数です。 追加。
現在、デコレータを使用して、特定の関数、特にアクセスできない関数に retry
機能を追加できます。
retry
デコレータは、予測できない動作やエラーが発生する可能性があり、それらが発生したときに同じ操作を再試行するシナリオで役立ちます。
典型的な例は、for
ループ内で失敗したリクエストを処理することです。 そのようなシナリオでは、retry
デコレータを使用して、その特定のリクエストを指定回数だけ再試行することを管理できます。
@retry
を使用して Python でコード ブロックを再試行する
retry
デコレータには、この機能を提供するさまざまなライブラリがあり、そのようなライブラリの 1つが retrying
ライブラリ です。
これにより、wait
および stop
条件を Exceptions
から期待される戻り値まで指定できます。 retrying
ライブラリをインストールするには、次のように pip
コマンドを使用できます。
pip install retrying
それでは、0
と 10
の間の数字をランダムに作成し、数字が 1
より大きい場合に ValueError
を発生させる関数を作成しましょう。
import random
def generateRandomly():
if random.randint(0, 10) > 1:
raise ValueError("Number generated is greater than one")
else:
return "Finally Generated."
print(generateRandomly())
その時点で生成された数値が 1 より大きい場合、コード出力は次のようになります。
Traceback (most recent call last):
File "c:\Users\akinl\Documents\Python\SFTP\test.py", line 11, in <module>
print(generateRandomly())
File "c:\Users\akinl\Documents\Python\SFTP\test.py", line 6, in generateRandomly
raise ValueError("Number generated is greater than one")
ValueError: Number generated is greater than one
コードに ValueError
がスローされる状況はあり得ないので、retry
デコレーターを導入して、ValueError
が発生しなくなるまで generateRandomly()
関数を再試行できます。
import random
from retrying import retry
@retry
def generateRandomly():
if random.randint(0, 10) > 1:
raise ValueError("Number generated is greater than one")
else:
return "Finally Generated."
print(generateRandomly())
出力:
Finally Generated.
ここで、retry
デコレータは、ValueError
がなくなるまで random
操作を再試行し、文字列 Finally Generated.
のみが得られます。
if
ブロック内に print()
ステートメントを導入することで、コードが generateRandomly()
を再試行した回数を確認できます。
import random
from retrying import retry
@retry
def generateRandomly():
if random.randint(0, 10) > 1:
print("1")
raise ValueError("Number generated is greater than one")
else:
return "Finally Generated."
print(generateRandomly())
出力:
1
1
1
1
1
1
1
Finally Generated.
ここでは 8
ですが、コードを実行すると異なる場合があります。 ただし、コードが長時間再試行し続ける状況はあり得ません。 したがって、stop_max_attempt_number
や stop_max_delay
などの引数があります。
import random
from retrying import retry
@retry(stop_max_attempt_number=5)
def generateRandomly():
if random.randint(0, 10) > 1:
print("1")
raise ValueError("Number generated is greater than one")
else:
return "Finally Generated."
print(generateRandomly())
出力:
1
1
1
Finally Generated.
関数は 5
回だけ再試行されますが、5 回目より前に成功するか、値 Finally Generated.
を返すか、失敗して ValueError
をスローします。
1
1
1
1
1
File "C:\Python310\lib\site-packages\retrying.py", line 247, in get
six.reraise(self.value[0], self.value[1], self.value[2])
File "C:\Python310\lib\site-packages\six.py", line 719, in reraise
raise value
File "C:\Python310\lib\site-packages\retrying.py", line 200, in call
attempt = Attempt(fn(*args, **kwargs), attempt_number, False)
File "c:\Users\akinl\Documents\Python\SFTP\test.py", line 9, in generateRandomly
raise ValueError("Number generated is greater than one")
ValueError: Number generated is greater than one
tenacity
を使用して Python でコード ブロックを再試行する
retrying
ライブラリは少し変わっている可能性があり、もはや維持されていませんが、tenacity
ライブラリ はそのすべての機能に使い捨てのより多くのツールを提供します。
tenacity
をインストールするには、次の pip
コマンドを使用します。
pip install tenacity
3
で stop
試行を使用して同じコードを試すことができます。
import random
from tenacity import retry, stop_after_attempt
@retry(stop=stop_after_attempt(3))
def generateRandomly():
if random.randint(0, 10) > 1:
print("1")
raise ValueError("Number generated is greater than one")
else:
return "Finally Generated."
print(generateRandomly())
3 回の試行時間枠内で、生成された乱数が 1 未満の場合のコードの出力。
1
Finally Generated.
ただし、そうでない場合は、以下の出力がスローされます。
1
1
1
Traceback (most recent call last):
File "C:\Python310\lib\site-packages\tenacity\__init__.py", line 407, in __call__
result = fn(*args, **kwargs)
File "c:\Users\akinl\Documents\Python\SFTP\test.py", line 9, in generateRandomly
raise ValueError("Number generated is greater than one")
ValueError: Number generated is greater than one
The above exception was a direct cause of the following exception:
Traceback (most recent call last):
File "c:\Users\akinl\Documents\Python\SFTP\test.py", line 14, in <module>
print(generateRandomly())
File "C:\Python310\lib\site-packages\tenacity\__init__.py", line 324, in wrapped_f
return self(f, *args, **kw)
File "C:\Python310\lib\site-packages\tenacity\__init__.py", line 404, in __call__
do = self.iter(retry_state=retry_state)
File "C:\Python310\lib\site-packages\tenacity\__init__.py", line 361, in iter
raise retry_exc from fut.exception()
tenacity.RetryError: RetryError[<Future at 0x29a75442c20 state=finished raised ValueError>]
Olorunfemi is a lover of technology and computers. In addition, I write technology and coding content for developers and hobbyists. When not working, I learn to design, among other things.
LinkedIn