追記:ここに書いてることって「カリー化」と「部分適用」を勉強したらもっと整理される気がするので、あまり参考にしないように。
def gen_func_1arg(func): def func_1arg(x): return func(x, 15) return func_1arg @gen_func_1arg def func_x(x, y): print(x + y) return 1 func_x(4)
…①
メインは xとy の合計をprintする func_x(x, y) なのだが、それをxだけの一変数関数オブジェクトとして後程使いまわしたい要求があって、yは実行時に argv 経由で与えられることを想定している。
すると、上のコードは y=15 が gen_func_1arg 関数内にハードコーディングされているので要求を満たしていない。
デコレータには引数を渡すことができる。その場合、デコレータ関数はデコレータ関数を返すデコレータ関数になる。
def def_y(y): def gen_func_1arg(func): def func_1arg(x): return func(x, y) return func_1arg return gen_func_1arg @def_y(15) def func_x(x, y): print(x + y) return 1 func_x(4)
…②
これで、15をデコレータ関数から引きはがすことができた。 しかし、func_x の定義からは引きはがせない。
def gen_func_1arg(func, y): def func_1arg(x): return func(x, y) return func_1arg def func_x(x, y): print(x + y) return 1 func_x = gen_func_1arg(func_x, 15) func_x(4)
…③
デコレータを使わずにこのようにすることで要求を満たすことができた。
何をしたか。①に舞い戻って、デコレータ関数 gen_func_1arg
を func_x
に適用する手順を func_x = gen_func_1arg(func_x, 15) という形で冗長に書いた。それに伴って、デコレータ関数は関数と固定する変数の2つを引数に取る形に変更してシンプルにした。
def gen_func_x(y): def func_x(x): print(x + y) return 1 return func_x func_x = gen_func_x(15) func_x(4)
…④
スコープの関係を使うと、このようにすることもできる。func_x(x, y)のyは一つ外側の関数 gen_func_x
のスコープで与えられる。この書き方にすると、y の固定だったり、xの固定だったり、yを加工してから固定だったり、といった作業が必要な場合に func_x(x, y)
が使いまわせないので、その場合は③が有用だと思う。
参考:
- Python - デコレータ
- Python: 色々なデコレータの作り方と使い方、そして本質 | CUBE SUGAR STORAGE デコレータの書き方はシンタックスシュガーにすぎないので、本質的に何をしているかを意識せよという話。上の③や④はシンタックスシュガーを使わずにデコレーションしていることになる。
- Pythonのデコレータを理解するための12Step - Qiita