デコレータ用の関数を外部から指定する方法
環境
- Python 3.7
背景
PythonでWeb Apiのクライアントライブラリを作成しています。APIのアクセス過多で失敗したときでもリトライするよう、my_retry
というデコレータを作成しました。
def my_retry(self, function):
"""
HTTP Status Codeが429 or 5XXのときはリトライする. 最大5分間リトライする。
"""
@functools.wraps(function)
def wrapped(*args, **kwargs):
def fatal_code(e):
"""Too many Request以外の4XXはretryしない"""
code = e.response.status_code
return code != 429 and code < 500
return backoff.on_exception(backoff.expo, requests.exceptions.RequestException,
jitter=backoff.full_jitter,
max_time=300,
giveup=fatal_code)(function)(*args, **kwargs)
return wrapped
以下、読みやすさのために my_retry
を簡略化しています。
# coding: utf-8
import functools
def my_retry(function):
@functools.wraps(function)
def wrapped(*args, **kwargs):
print("my_retry calls", function.__name__, end=", ")
return function(*args, **kwargs)
return wrapped
class ApiClient:
def __init__(self):
pass
@my_retry
def execute_hoge_api(self):
print("hoge!")
@my_retry
def execute_fuga_api(self):
print("fuga!")
def main():
ac = ApiClient()
ac.execute_hoge_api()
ac.execute_fuga_api()
if __name__ == '__main__':
main()
やりたいこと
ApiClient
クラスのユーザが、リトライ用の関数を変更できるようにしたいです。
具体的には、ApiClient
のコンストラクタ引数にリトライ用関数を指定するなどの方法を考えています。
どのようなコードを書けばよいでしょうか?
検討したこと
以下のコードのように、my_retry
関数をApiClient
クラスのインスタンスメソッドにしてみました。
この場合、@my_retry
の引数には何を渡せばよいか分からず、詰まってしまいました。
class ApiClient:
def __init__(self, my_retry=None):
if my_retry is not None:
self.my_retry = my_retry
pass
# デコレータの引数には何を指定すればよい?
@my_retry
def execute_hoge_api(self):
print("hoge!")
@my_retry
def execute_fuga_api(self):
print("fuga!")