デコレータ
デコレータとは?
-
前提
- Pythonは引数に関数さえ普通にオブジェクトとして渡せる!
- これは本当に書いたままの意味
- 普段こういうコーディングをしていなかった
- つまりデコレータを使っていなかった、ということにも近しいか。
- Pythonは引数に関数さえ普通にオブジェクトとして渡せる!
-
デコレータとは、関数をラップし、新たな結果を返すもの
- 事前・事後(どちらでもいい)に処理を追加できる
- ラップする関数を指定回数、連続実行するとかにしてもいい。
- デコレータはcallable である
- callable=引数を取って結果を返す、呼び出し可能なオブジェクトの総称
- decoratorはcallableであるとは、何か当たり前のことを言っているだけな気がする。
-
反して、
デコレータは必ずしもcallableを返す必要はない
- python構文上、どのような関数もデコレータとして使用できる
- よってデコレータにreturnが無い、という形式が文法上は成り立つ
- 実行時にはエラーになるということ?
- 使い方があるのか要確認。でもいったん置いておく。
-
使われ方で多いのは、自信をラップして置き換えてしまうこともある
- 使うと混乱しそう。可読性が・・
python foo = outer(foo)
- なお、ラップする側の関数の名前やdocstringが、もとの関数のそれを上書きする。
- 抑止するためには
-
from functools import wraps
- docstringや関数名を保持することが出来るらしい。
- これもいったんは置いておく。
-
- 抑止するためには
- 使うと混乱しそう。可読性が・・
-
シンタックスシュガー
-
要は簡易表記。以下どちらも同じ。
- パターン1
python foo = outer(foo)
- パターン2(シンタックスシュガー)
python @outer def foo(): # def of foo pass
- パターン3を記憶しておいたほうが良さそう
-
パターン3(シンタックスシュガー)
-
デコレータに関数以外の引数がある場合
python @outer() def foo(): # def of foo pass
-
このときデコレータは以下の書き方になる。ラップのラップ、みたいな構造で書く必要がある。 ```python def outer(additional=3):
def actual_outer(function): # 以降はcode例と同じ(略) return actual_outer
```
-
- パターン1
-
-
アンパックを使ってデコレータを汎化できる
*args
は位置引数のタプル**kwargs
はキーワード引数の辞書- 呼び出し方によってどちらかが使われる、という理解
Code
とりあえず関数実装。クラス実装もあるが省略。
"""
decorator example
* as function
* with syntax sugar
"""
def mydecorator(function):
def wrapped(*args, **kwargs):
print(args)
print(kwargs)
# something pre-exec here
print("pre-exec")
result = function(*args, **kwargs)
# something post-exec here
print("post-exec")
return result
return wrapped
# decorated function with syntax sugar
@mydecorator
def mydecorated(a = 1, b = 2):
print("original function, a:{}, b:{}".format(a, b))
mydecorated(3, 4)#args will used
mydecorated(a=3, b=4)#kwargs will used
実行結果
(3, 4)
{}
pre-exec
original function, a:3, b:4
post-exec
()
{'a': 3, 'b': 4}
pre-exec
original function, a:3, b:4
post-exec
Future work、でもとりあえずやらなくても大丈夫
- デコレータの例文で静的なメソッドとクラスメソッドを並べている書籍がある。
- けれど、結果など併記してなくて何を言いたいのか分かっていない。
- 2者の違いから理解し、テスト実行の必要あり。
- デコレータがcallableを返さない場合、実行時にエラーとなるのか?
- それなら、結局許されないのに等しいのか?
- それともなにか、使い道があるのか?
from functools import wraps
のテスト