前の投稿からの続きです。 前回見た第一級関数と無名関数の知識を元に話を進めます。
デコレータは「関数を引数に受け取って、関数を返す関数」です。
言葉遊び的です。──とりあえず言われたとおりに書いてみます。
>>> def decorator(a_func):
... return (lambda: True)
...
受け取った関数は使ってませんし、返す関数は引数なしでTrueを返すだけですが、これでも要求通りです。
>>> def hoge():
... return 'hoge'
...
>>> h = decorator(hoge)
>>> h()
True
関数hogeを渡しても、使っていないので何も起きず、呼び出すとTrueを返す関数が返って来ています。 よく解らないものが出来あがりました。
hogeから見たデコレータ
こういった時は主観、つまり視る立場を変えて考えます。 ここではデコレータ側ではなく、hoge関数の立場になってみます。
hogeがデコレータに期待することは、 「その名前からして、何か装飾をしてくれるのだろう」ということです。 ならばということで、自分自身に代入してみます。
# hoge「恰好よくしてください」
# decorator「OK!」
>>> hoge = decorator(hoge)
>>> hoge()
True
恰好よくなったのか解りかねますが、Trueしか返せなくなりました。 困ります。
>>> def hoge():
... return 'hoge'
...
元に戻します。 ところで、Pythonでは、定義が複数回表われた場合も音もなく上書きしてしまいます。 便利ですが、危険で不便です。しかし、先に理解していれば問題ありません。 この辺のPythonのポリシーについてはPython / 不便が便利に似た話を書きました。
さて。とにかく、もっと腕のよいデコレータが必要です。
>>> def decorator(a_func):
... return a_func
...
このデコレータは受けとった関数をただ返すだけです。使ってみます。
# hoge「恰好よくしてください」
# decorator「OK!」
>>> hoge = decorator(hoge)
>>> hoge()
'hoge'
当然ですが、変ってません。元に戻す必要もないほどです。次にいきます。
>>> def decorator(a_func):
... return (lambda:('KOOL', a_func()))
...
無名関数が出てきました。恰好よさそうですね。きちんと渡した関数も呼び出しています。
# hoge「恰好よくしてください」
# decorator「OK!」
>>> hoge = decorator(hoge)
>>> hoge()
('KOOL', 'hoge')
'KOOL'と'hoge'のタプルが返ってきています。
hogeの恰好よさが上がりました。 これがデコレータです。関数の機能を後から拡張したいときに使います。
要求があって機能を作ったのではなく、 機能があって要求を推測したので理解の流れが逆行しています。 あえて書き進めてみました。なんとなくでも、意味が伝わるといいのですが。
デコレータの略記
Pythonデコレータというと、@を使うものだというのが一般的な理解です。
>>> @decorator
... def hoge():
... return 'hoge'
...
>>> hoge()
('KOOL', 'hoge')
ここまで読んだ方は@記法が単なる定義と代入の別記法に過ぎないことが解っていると思います。
>>> def hoge():
... return 'hoge'
...
>>> hoge = decorator(hoge)
>>> hoge()
('KOOL', 'hoge')
@記法により、簡単にデコレータを適用できるようになるので便利です。
>>> @decorator
... def fuga():
... return 'fuga'
...
>>> fuga()
('KOOL', 'fuga')
>>> @decorator
... def var():
... return 'var'
...
>>> var()
('KOOL', 'var')
──続きます。
0 件のコメント:
コメントを投稿