任意の関数にmiddleware的な何かを追加する方法
memo: 任意の関数にmiddleware的な何かを追加する方法。
例えばこういうような使い方。元となる関数fがある。
def f(x): return x * x
これを以下のような呼び出し関係になるfoo,barで包んだnew_fを作りたい。
begin foo begin bar f() end bar end foo
ポイントとしては、以下の2つが存在して欲しい。
- 元となる関数の呼び出し前のhook
- 元となる関数の呼び出し後のhook
このようなhookの利用の仕方は以下のようになる。
def foo_middleware(context, create): # 呼び出し前のhook # do_something() # createが呼ばれる = 内部の関数が呼ばれる value = create(context) # 呼び出し後のhook # do_something(value) return value
middlewareはcontextという何か設定値を共有できる辞書と元の関数呼び出しを行うclosureを引数として取る関数。 ちなみに内部の関数に呼び出しをスキップして結果を返したい場合にはこのclosureを呼ばずにreturnすれば良い。
全体とつなげた使い方は以下の様になる。MiddlewareApplicatorが必要となるクラス
if __name__ == "__main__": # target function def f(x): return x * x def foo_middleware(context, create): print("foo: before create (context={})".format(context)) context["marker"] = 1 value = create(context) print("foo: after create (value={}, context={})".format(value, context)) return value def bar_middleware(context, create): print("bar: before create (context={})".format(context)) context["marker"] += 1 value = create(context) print("bar: after create (value={}, context={})".format(value, context)) return value new_f = MiddlewareApplicator([foo_middleware, bar_middleware])(f) print(new_f(10))
以下のような結果を返す。
foo: before create (context={'_keys': [], '_args': (10,)}) bar: before create (context={'_keys': [], 'marker': 1, '_args': (10,)}) bar: after create (value=100, context={'_keys': [], 'marker': 2, '_args': (10,)}) foo: after create (value=100, context={'_keys': [], 'marker': 2, '_args': (10,)}) 100