概要
Python のデコレータは関数の前後に処理を入れたり関数の引数のチェックなどが行なえます
今回は自作のデコレータを作成して挙動を確認してみました
環境
- macOS 10.15.5
- Python 3.8.3
最初のステップ
まずはデコレータの雛形を作成します
デコレータ自体は特に何もしていないため test メソッドの内容がそのまま出力されます
vim 1.py
def first_deco(func):
def wrapper(*args, **kwargs):
func(*args, **kwargs)
return wrapper
@first_deco
def test():
print("hello")
test()
python 1.py
=> hello
func(*args, **kwargs)
が test メソッド本体になります
なのでこの前後に何か処理を書くことで前後の処理を定義できます
デコレータに引数をつける
次にデレコータに引数をもたせてみます
一つ階層を上げてまず引数を受け取る関数を定義するのがポイントです
今回はデコレータに指定されたメッセージを本体の関数がコールされたあとに表示するようにしています
vim 2.py
def first_deco(msg):
def _first_deco(func):
def wrapper(*args, **kwargs):
func(*args, **kwargs)
print(msg) # 本体の関数のあとに msg を表示する
return wrapper
return _first_deco
@first_deco(msg="world")
def test():
print("hello")
test()
=> hello world
デコレータを付与した関数の引数を扱う
デコレータを付与した関数をデコレータ内で扱ってみます
関数の引数は args と kwargs にそのまま入ってきます
vim 3.py
def first_deco(func):
def wrapper(*args, **kwargs):
func(*args, **kwargs)
print(args[0])
print(kwargs["post_msg"])
return wrapper
@first_deco
def test(msg, post_msg=""):
print("hello")
test("world", post_msg="!!")
# test("world") => KeyError: 'post_msg'
=> hello world !!
kwargs は本体の関数を呼び出した際に指定がないとデコレータ側には届かないようです
要するにで kwargs のデフォルト値は関数本体にしか影響を与えないようです
レスポンスがある場合
関数本体に return がある場合はデコレータ内でもちゃんと return を書く必要があります
vim 4.py
def first_deco(msg):
def _first_deco(func):
def wrapper(*args, **kwargs):
return func(*args, **kwargs) + msg
return wrapper
return _first_deco
@first_deco(msg="world")
def test():
return "hello"
print(test())
=> hello world
普通の関数としても使える
デコレータとして関数に付与しなくても普通の関数として使うこともできます
first_deco
にキーワード引数を与えてその戻り値に関数本体である test を渡して最後に test に必要な引数を与えています
vim 5.py
def first_deco(msg):
def _first_deco(func):
def wrapper(*args, **kwargs):
return func(*args, **kwargs) + msg
return wrapper
return _first_deco
def test():
return "hello"
print(first_deco(msg="world")(test)())
=> hello world
最後に
Python のデコレータの機能を使ってみました
とりあえずは関数の前後処理を実装するためのものだと思っておけば良さそうです
調べるといろいろとサンプルコードが出てくるのでデコレータを作ること自体そんなに大変ではなりですが実際に手を動かしてサンプルを作ってみることでより理解が深まるかなと思います
0 件のコメント:
コメントを投稿