pythonのデコレータが良く分かっていなかったので自分なりに整理してみた。
デコレータとは?
関数を関数で包む為の簡単な書き方(シンタックスシュガー)。具体的には関数hogeの前に@decoと付けるとhoge=deco(hoge)となる。
#デコレータ関数 def deco(func): def _deco(): print "start" func() print "end" return _deco #デコレータ対象関数 @deco def hoge(): print "hoge" hoge() #実行結果 start hoge end
上記の場合、関数hogeが関数decoにラッピングされた形で実行される。これは@decoを関数hogeの前に付ける事により、関数hogeが関数deco(hoge)に置き換えられる為である。本来であればhoge=deco(hoge)と書かなければならないところをデコレータを使用する事で@decoを関数の前に書くだけで同じ動きをする事となる。
なお、デコレータ関数はデコレータ対象関数を引数として受け取る。その為、必ず引数が受け取れる形でなければならない。また、デコレータ関数の戻り値をデコレータ対象関数へ代入する為、デコレータ関数の戻り値は必ず関数でなければならない。(文字列を返してもいいが関数としては実行出来ない。また戻り値を返さない場合はデコレータ対象関数が無くなる為実行出来ない。)
※デコレータ関数にて引数を受け取れない場合
#デコレータ関数(引数無し) def deco(): def _deco(): print "start" func() print "end" return _deco #デコレータ対象関数 @deco def hoge(): print "hoge" hoge() #実行結果 ※関数decoが引数を受け取れない為エラーとなる。 Traceback (most recent call last): File "D:\work\test\decotest.py", line 217, in <module> @deco TypeError: deco() takes no arguments (1 given)
※デコレータ関数にて戻り値を返却しない場合
#デコレータ関数 def deco(func): def _deco(): print "start" func() print "end" #return _deco 戻り値を削除 #デコレータ対象関数 @deco def hoge(): print "hoge" hoge() #実行結果 ※関数hogeが存在しない為エラーとなる Traceback (most recent call last): File "D:\work\test\decotest.py", line 220, in <module> hoge() TypeError: 'NoneType' object is not callable
デコレータのパターン
多分これぐらい覚えれば何とかなると思われる。
1.基本的なパターン
※シンタックスシュガー:hoge=deco(hoge)
#デコレータ関数 def deco(func): def _deco(): print "start" func() print "end" return _deco #デコレータ対象関数 @deco def hoge(): print "hoge" hoge() #実行結果 start hoge end
2.デコレータ対象関数が引数を持つパターン
※シンタックスシュガー:hoge=deco(hoge)
#デコレータ関数 def deco(func): def _deco(*args,**kwargs): #引数を受け取れる様にする print "start" func(*args,**kwargs) #引数を渡す print "end" return _deco #デコレータ対象関数 @deco def hoge(arg): print "hoge" + arg hoge("HOGE") #実行結果 start hogeHOGE end
3.デコレータ関数が引数を持つパターン
※シンタックスシュガー:hoge=deco(arg)(hoge)
#デコレータ関数 def deco(arg): #引数を受け取れる様にする("HOGE"を受け取る) def _deco(func): #引数を受け取れる様にする(関数hogeを受け取る) def __deco(): print "start" print arg func() print "end" return __deco return _deco #デコレータ対象関数 @deco("HOGE") def hoge(): print "hoge" hoge() #実行結果 start HOGE hoge end
4.デコレータ関数が複数パターン
※シンタックスシュガー:hoge=deco1(deco2(hoge))
#デコレータ関数1 def deco1(func): def _deco1(): print "start deco1" func() print "end deco1" return _deco1 #デコレータ関数2 def deco2(func): def _deco2(): print "start deco2" func() print "end deco2" return _deco2 #デコレータ対象関数 @deco1 @deco2 def hoge(): print "hoge" hoge() #実行結果 start deco1 start deco2 hoge end deco2 end deco1
5.デコレータ関数がクラスパターン1
※シンタックスシュガー:hoge=Deco(hoge))
#デコレータ関数用クラス class Deco(): def __init__(self,func): self.func=func #関数として使用出来る様に__call__を使用 def __call__(self): print "start" self.func() print "end" @Deco def hoge(): print "hoge" hoge() #実行結果 start hoge end
6.デコレータ関数がクラスパターン2
※シンタックスシュガー:hoge=deco.deco(hoge)
#デコレータ関数用クラス class Deco(): def deco(self,func): def _deco(): print "start" func() print "end" return _deco deco=Deco() @deco.deco def hoge(): print "hoge" hoge() #実行結果 start hoge end
まとめ
デコレータを一番手っ取り早く理解する方法はシンタックスシュガーを覚える事だと思う。考えるな、感じろ!がデコレータ理解のポイント。