読者です 読者をやめる 読者になる 読者になる

Pythonのデコレータとは何者か?

最近やっとPythonのデコレータがわかってきたのでなぜわからなかったのか、そして結局どういうものなのか書いておく。

Pythonのデコレータのわかりにくい理由はまず挙げられているサンプルがよくないのだと思う。

def hoge(func):
	print "hoge"

@hoge
def bar():
	print "bar"

でこれで実行するとhogeが出力されるとか何がなされているのか意味不明だ。

def hoge(func):
	print "hoge"

def bar():
	print "bar"
bar = hoge(bar)

さらに以上のサンプルと同値であるといわれても余計何のこっちゃ?となる。
さらに高階関数を使い始めてとかいうサンプルまで存在する。
要するに難しく見える理由は何かというといくつもの知識が必要とされていてそれがなんの断りもなしに使われているかということではないだろうか?

文句ばっかり言っててもあれなので解説していこう。Pythonチュートリアルの知識程度で読めるもので書いていくつもりだ。
まず、注意してほしいのはPythonではすべてがオブジェクトだ。関数も例外ではない。
何がいいたいかというと関数に代入できてしまうのだ。以下のサンプルを見てほしい。

def func():
	pass

func = 2
print func

これを実行すると2が表示される。キモはfuncに2を代入しているところにある。
funcというのは所詮何もしない(pass)という動作が入った変数(オブジェクト)に過ぎないので普通の変数と同じように代入ができる。だから2を代入できてしまうのだ。

もうひとつ重要なことがある。関数に関数を渡せるということだ。
mapとかに関数を渡すので使っているかもしれないが一応書いておく。

def deco(func):
	print func(2)+2

def foo(n):
	return 2*n

deco(foo)

decoは関数を受け取る関数でそれにfooを渡している。


ここまでくればあと少しだ。

def deco(func):
	print func(2)+2

def foo(n):
	return 2*n

n = deco(foo)

と書いても先ほどと同じ結果を返す。
次にこのnをfooに置き換えても同じ結果を返しそうだ。

def deco(func):
	print func(2)+2

def foo(n):
	return 2*n

foo = deco(foo)

こうしてなんのメリットがあるのか?ということだが、クラスのメソッドが云々らしいが僕はよく理解していない...
さて、これはすこし不恰好ではないだろうか?そこでこれと等価な書き方としてPythonにはデコレータが用意されている。

def deco(func):
	print func(2)+2

@deco
def foo(n):
	return 2*n

とかけば完全に同じだ。とデコレータに到達することができた。これはfooをdecoでデコレートしている。

ではこのデコレータが何に役に立つか?ということだがそれは他のサイト・ブログで詳しく解説されているのでそちらを参考にしたほうがいいと思う。ここまで読めたら奇怪にみえたデコレータも少し見えてきたはずだ。