デコレーター_1(Python_38) (original) (raw)
この連載では、Pythonについて色々な形で再学習に取り組んでいます。前回の記事はこちらになります。
前回は、イテレータについて学びました。イテラブル、イテレータの仕組みがわかったと思います。
今回は、デコレーターです。クラスのスタティックメソッド、クラスメソッドを学んだ時に出てきました。複数の関数の前後に決まった処理を追加したいとき、その処理をまとめておくと便利です。
関数のカスタマイズ
関数の中身を変更せずに機能追加するということは、関数の前後に処理を追加することになります。以下のようなイメージになります。
前処理 対象の関数呼び出し 後処理
これでは普通のプログラムなので、この処理自体を関数にまとめてしまいます。デコレートする関数自体は、この関数の引数として渡してしまいましょう。Pythonでは関数自体もオブジェクトですので、このような記述が可能です。
def 関数(対象の関数): 前処理 対象の関数呼び出し 後処理
実際の例を見てみましょう。
def deco(func): print('decoの前処理が実行されました') func() print('decoの後処理が実行されました')
def check(): print('checkが実行されました')
check() # checkが実行されました
deco(check)
decoの前処理が実行されました
checkが実行されました
decoの後処理が実行されました
この例のように「check()」と、関数名の最後に"()"が付く場合は関数を実行します。「deco(check)」におけるcheckのように"()"が付かない場合は関数自体を意味します。 関数checkを引数に指定して関数decoを実行すると、処理をまとめて実行します。
デコレーター
デコレーターは、関数やメソッド、クラスの定義の前に記述(デコレート)することで、中身を変更せずに特定の処理を追加できる機能です。追加する機能を記述した関数を作成して、対象の関数をデコレートします。以下のように記述します。
def デコレーター関数(デコレートする関数): def ラッパー関数(): 前処理 デコレートする関数の呼び出し 後処理 return ラッパー関数
引数で指定したデコレートする関数に、前後の処理を追加した関数(ラッパー関数)を定義して返しています。Pythonでは関数自体もオブジェクトなので、このようなことも可能なのです。
返ってきた関数を実行すると、まとめて処理を実行します。デコレートする関数は、デコレーター関数の引数として指定されています。ラッパー関数は、上のスコープで指定された内容をデコレートする関数として参照しています。
デコレートする関数を実行するには、以下のように記述します。
関数の定義
def デコレートする関数(): # 処理
呼び出し
デコレーター関数(デコレートする関数)()
「デコレーター関数(デコレートする関数)」には、デコレーター関数内のラッパー関数が定義され、最後に「()」を付けることで呼び出しています。
実際の例を見てみましょう。
def deco(func): print('decoが実行されました') def wrap(): print('wrapの前処理が実行されました') func() print('wrapの後処理が実行されました') return wrap
def check(): print('checkが実行されました')
deco(check)()
decoが実行されました
wrapの前処理が実行されました
checkが実行されました
wrapの後処理が実行されました
「deco(check)」はdeco関数が実行された結果(wrap関数)を意味し、「deco(check)()」で、その関数を実行します。
ところで先にデコレーターのことを「関数やメソッド、クラスの定義の前に記述(デコレート)することで、中身を変更せずに特定の処理を追加できる機能」とご紹介しました。実をいうと、上の呼び出し方法は、以下のように簡略化して記述できます。
関数の定義
@デコレーター関数 def デコレートする関数(): # 処理
呼び出し
デコレートする関数()
実際の例を見てみましょう。
def deco(func): print('decoが実行されました') def wrap(): print('wrapの前処理が実行されました') func() print('wrapの後処理が実行されました') return wrap
@deco def check(): print('checkが実行されました')
check()
decoが実行されました
wrapの前処理が実行されました
checkが実行されました
wrapの後処理が実行されました
このように記述すると「@deco」で一度deco関数が実行されます。結果、check関数がdeco関数内のwrap関数に書き換わります。
シンプルな記述で同様の結果が得られました。
次回はデコレーターの応用
いかがでしょうか。デコレーターはおもしろい機能ですね。でも、ここまでやらなくても最初にご紹介した例でいいんじゃないでしょうか? 次回はデコレーターの使いどころと、応用方法について学ぼうと思います。お楽しみに!!