デコレータについて学んでいきましょう。
事前知識
デコレータを学ぶ上では、関数内関数とクロージャについて理解しておく必要があります。
クロージャで、引数を関数にする
デコレータのポイントは、クロージャにおける引数が関数になっている。ということです。
クロージャについて簡単に復習をすると、事前に複数のパラメーターを入れておくことによって違う条件における計算が簡単になる、というものでした。
そして、クロージャにおけるパラメータを関数にしたものがデコレータです。
具体的なコードで見ていきましょう。
コード1 def outer(func):
2 def inner(a, b):
3 print('decorated!')
4 func(a, b)
5 return
6 return inner
7 def minus(c, d):
8 print(c - d)
9 return
10 decorate = outer(minus)
11 decorate(10, 5)
アウトプットdecorated!
5
コードの解説(1) outer関数が定義され、引数としてfuncを取っています。6行目でinnerを返していますが、これはinner関数自体を示しており、関数を実行しているわけではありません。
(2) inner関数の中では、decorated!という文字列が出力されるコードと、func(a, b)というコードがあります。
このfunc(a, b)というのは、outer関数の引数です。
つまり、outer関数の引数が関数のアドレスを示していれば、その関数が実行されるということです。
(3) 7行目では、minusという関数が定義されています。これは、cとdという2つの引数を取り、それらを引いた結果を出力します。
(4) ここからがポイントです。10行目でminusを引数にしてouter関数を実行しています。outer関数はinner関数が入っているアドレスを返します。
つまり、具体的にはdecorate = innerとなり、さらに引数としてminusを覚えているという状態になるのです。
(5) decorate(10, 5)というコードで、inner関数を実行することになります。inner関数の引数は10と5です。
まずは、3行目のprint関数が実行され、decorated!が出力されます。
次に4行目が実行されます。funcというのは、outer関数実行時の引数であり、今回はminusという関数のアドレスが格納されていました。
つまり、func(a, b)というのは、minus(a, b)となるのです。
そして、aとbはinner関数を呼び出した時の引数(10と5)です。その結果、minus関数が引数10と5として実行されますので、10 - 5の5が出力されるのです。
デコレータとは
上記のコードでは、decorate = outer(minus)とouter関数を実行した上で、decorate()としてinner関数を実行しました。
結果としてコードが2行になってしまっています。
そこで、コードを更に簡潔にするために使われるのがデコレータです。
具体的にデコレーターを使ったコードを見てみましょう。
コード1 def outer(func):
2 def inner(a, b):
3 print('decorated!')
4 func(a, b)
5 return
6 return inner
7 @outer
8 def minus(c, d):
9 print(c - d)
10 return
11 minus(10, 5)
7行目に@outerというコードを書きましたが、これがデコレータです。
このコードを使うことで、minus(10, 5)と一行のコードを書くだけで、outer関数とinner関数を呼び出すことができるようになりました。
デコレータも中々理解をするのが難しい概念ですが、何回もコードを書いていくうちに慣れてきますので、この記事をよみながら実践してみると良いでしょう。
デコレータのまとめ
(1) コードをすっきりと書くために使われるのがデコレータ
デコレータを学んだ後は
さらに高度なpropertyについて学んでいきましょう。しかし、propertyを理解するためには属性への参照について理解する必要がありますので、まずは属性の参照についてわかりやすく解説という記事を読んでいきましょう。