デコレータ
高階関数 を上手に使うと、ある関数を引数に受け取って、その関数の中身を変えることなく、高階関数自身に定義されている機能を付け加えることができます。そのようなコードのシンタックスシュガー(簡略記法)が デコレータ (decorator) とよばれる構文です (decorator には「装飾するもの」という意味があります)。デコレータを使えば処理内容が微妙に異なるだけの関数をあれこれ作る必要がなくなります。
デコレータによる機能の追加
デコレータの記法を使うときは、まずデコレータを定義してから、デコレート(装飾)される関数の前に、
を添えます。簡単な例を見てみましょう。
# HIGHER_01
# 高階関数の定義
def hello(func):
def inner():
print("Hello!")
func()
return inner
# how()を定義して、hello()で装飾
@hello
def how():
print("How's it going?")
# how()を実行
how()
Hello! How's it going?
how() は "How's it going?" (調子はどう?) という文字列を表示する関数です。
hello() は関数を受け取って、
・"Hello!" と表示する
・受け取った関数を実行する
という inner()関数を作って返す関数です。how() を hello() でデコレート(装飾)し、how() を実行すると、
・"Hello!" と表示する
・ how() を実行して "How's it going?" を表示する
という結果になります。つまり元々の how() が持つ機能に "Hello!" と表示する機能が追加されたことになります。
冒頭に説明したように、デコレータ機能はあくまで単なるシンタックスシュガー(簡略記法)に過ぎないので、本質は高階関数の仕組みにあるということに注意してください。上のサンプルコードは次のコードをデコレータを使って書き換えただけです。
# HIGHER_02
# 高階関数の定義
def hello(func):
def inner():
print("Hello!")
func()
return inner
# how()を定義
def how():
print("How's it going?")
# hello()にhow()を渡して実行
hello(how)()
Hello! How's it going?
コードを比較すると、デコレータを使った記法がさほど簡略されていないように思えるかもしれませんが、hello(how)() のような書き方は普段見慣れないものなので、コードを読んだ人を戸惑わせてしまうかもしれません。この部分をもう少しわかりやすく記述すると次のようになります。
# HIGHER_03
# 関数オブジェクトを生成
my_func = hello(how)
# 関数を実行
my_func()
これならば hello() の引数に how() を渡して実行しているのだということは理解できますが、やや冗長な書き方です。デコレータの記法を用いると、hello() で how() をデコレートしていることがひと目でわかります。
中古価格 | ![]() |

デコレータによる機能の上書き
コード HIGHER_01 を再掲します。
# HIGHER_01
def hello(func):
def inner():
print("Hello!")
func()
return inner
@hello
def how():
print("How's it going?")
how()
Hello! How's it going?
inner() の関数ブロック(処理内容が書かれた部分)から func() という記述を取り去ってしまうと、どのような結果になるのかを予測するのは難しくないはずです。念のために確認しておきましょう。
# HIGHER_04
# 高階関数の定義
def hello(func):
def inner():
print("Hello!")
return inner
# how()関数を定義してhello()関数で装飾
@hello
def how():
print("How's it going?")
how()
Hello!
予想通り "Hello!" とだけ表示されました。hello() は内側で定義した inner() を返すだけですから当然のことです。how() を受け取ってはいますが、内部で受け取った関数をひとつも使っていないので、結果としてデコレータは how() の機能を完全に上書きする形になります。
デコレータによる合成関数の実装
合成関数 g(f(x)) を次のように定義します。
たとえば、x = 10 のとき、
と計算できます。この合成関数を Python のデコレータを使って実装してみましょう。
# HIGHER_05
# 高階関数の定義
def double_func(func):
def inner(t):
return func(t) * 2
return inner
# add_one()を定義して、double_func()で装飾
@double_func
def add_one(x):
return x + 1
x = add_one(10)
print(x)
22
double_func() は「受け取った関数を 2 倍にする関数」を内部で定義します。引数に add_one() を渡せば、2 * (x + 1) を計算する関数となります。サンプルコードにあるように、デコレートされた関数に x = 10 を渡せば 22 が返ります。
・tampering with the code コードの改変
tamper はもともと「不法に変える」とか「改ざん」するなど、かなりネガティブな意味の単語。でも現代では「オープンソースのコードを変える」というように、ポジティブな場面でも普通に使われるようになってきている。
・closed to modifications (コードを) 修正できない
直訳すると「修正に対して閉じている」。
・code readability コードの可読性
プログラミングの本やサイトを読んでいると、うんざりするほど目にする「可読性」。まあ、それだけ大事だってことです。
・henceforth 今後は
hence は「それゆえに」、forth は「前へ」。
二つ合わせて「それゆえに前へ」。つまり「今後は」となります。
・for brevity 簡潔に、すっきりとわかりやすく
brevity は「簡潔さ、短さ」の意。
コメントを書く