Python decoratorの簡単な練習1

デコレートと言えばデコレーション Python

decorator(デコレーター)が今一つ分かっていないので簡単な練習。

絵はdecoraotor => decorate => decoration => デコレーションケーキと言う事で。

まずは普通の関数を使ったファイルsample0.pyを作る

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
def printscript():
print("Hello world")
printscript()
def printscript(): print("Hello world") printscript()
def printscript():
    print("Hello world")

printscript()

これを実行すると

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
% python3 sample0.py
Hello world
% python3 sample0.py Hello world
% python3 sample0.py
Hello world

これはいつも通り。

これにまずはprint内容を書き換える為のdecoratorを追加。
書き換えたいfunction、deco(func)を書き、書き換えたい先のfunctionの上に@decoと付ける。
deco(func)はdeco(func)の中の関数wrapperを返す(return)ので、それがprintscript()の出力になる。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
def deco(func): # decorator関数の宣言、funcにはfunction printscript()が引数として与えられる
def wrapper(*args, **kwargs): # デコレーターの中身、*args, **kwargsはデコレートする関数の引数。幾つあっても大丈夫な書き方。
print("Good evening world")
return wrapper
@deco
def printscript():
print("Hello world")
printscript()
def deco(func): # decorator関数の宣言、funcにはfunction printscript()が引数として与えられる def wrapper(*args, **kwargs): # デコレーターの中身、*args, **kwargsはデコレートする関数の引数。幾つあっても大丈夫な書き方。 print("Good evening world") return wrapper @deco def printscript(): print("Hello world") printscript()
def deco(func): # decorator関数の宣言、funcにはfunction printscript()が引数として与えられる
    def wrapper(*args, **kwargs): # デコレーターの中身、*args, **kwargsはデコレートする関数の引数。幾つあっても大丈夫な書き方。
        print("Good evening world")
    return wrapper

@deco
def printscript():
    print("Hello world")

printscript()

出力がHello worldでは無く、decoratorで書き換えられたGood evening worldになっているのが分かる。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
% python3 Sample0.py
Good evening world
% python3 Sample0.py Good evening world
% python3 Sample0.py
Good evening world

次はプリント文を飾ってみたい。
下記をsample01.pyとして保存、実行。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
def deco(func): # decorator関数の宣言、funcにはfunction printscript()が引数として与えられる
def wrapper(*args, **kwargs): # デコレーターの中身、*args, **kwargsはデコレートする関数の引数。幾つあっても大丈夫な書き方。
print('*'*len("Hello world"))
func(*args, **kwargs) # 引数として渡された関数(printscript)を実行
print('*'*len("Hello world"))
return wrapper
@deco
def printscript():
print("Hello world")
printscript()
def deco(func): # decorator関数の宣言、funcにはfunction printscript()が引数として与えられる def wrapper(*args, **kwargs): # デコレーターの中身、*args, **kwargsはデコレートする関数の引数。幾つあっても大丈夫な書き方。 print('*'*len("Hello world")) func(*args, **kwargs) # 引数として渡された関数(printscript)を実行 print('*'*len("Hello world")) return wrapper @deco def printscript(): print("Hello world") printscript()
def deco(func): # decorator関数の宣言、funcにはfunction printscript()が引数として与えられる
    def wrapper(*args, **kwargs): # デコレーターの中身、*args, **kwargsはデコレートする関数の引数。幾つあっても大丈夫な書き方。
        print('*'*len("Hello world"))
        func(*args, **kwargs) # 引数として渡された関数(printscript)を実行
        print('*'*len("Hello world"))
    return wrapper

@deco
def printscript():
    print("Hello world")

printscript()

@decoでデコレートする名前の関数deco(func):を設定、このfuncにはデコレートした関数printscriptが引数として与えられる。

中の関数def wrapper(*args, **kwargs):のfunc(*args, **kwargs)でこの引数の関数(printscript)を実行。

今回はこの前後でHello worldと同じ長さの”*”を出力して挟み込むデコレートをする。
正に修飾。

最後にreturnで値を返し、この値が関数printscript()に返された事で、下記の通り出力される。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
% python3 sample1.py
***********
Hello world
***********
% python3 sample1.py *********** Hello world ***********
% python3 sample1.py
***********
Hello world
***********

このdecorator, 一旦設定すると色々な関数に使える。

こちらをsample1fl.pyとして保存する。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
def deco(func): # decorator関数の宣言、funcにはfunction printscript()が引数として与えられる
def wrapper(*args, **kwargs): # デコレーターの中身、*args, **kwargsはデコレートする関数の引数。幾つあっても大丈夫な書き方。
print('*'*len("Hello world"))
func(*args, **kwargs) # 引数として渡された関数(printscript)を実行
print('*'*len("Hello world"))
return wrapper
@deco
def printscript():
print("Hello world")
printscript()
@deco
def forloop():
for i in [1, 2, 3, 4, 5]:
print(i)
forloop()
def deco(func): # decorator関数の宣言、funcにはfunction printscript()が引数として与えられる def wrapper(*args, **kwargs): # デコレーターの中身、*args, **kwargsはデコレートする関数の引数。幾つあっても大丈夫な書き方。 print('*'*len("Hello world")) func(*args, **kwargs) # 引数として渡された関数(printscript)を実行 print('*'*len("Hello world")) return wrapper @deco def printscript(): print("Hello world") printscript() @deco def forloop(): for i in [1, 2, 3, 4, 5]: print(i) forloop()
def deco(func): # decorator関数の宣言、funcにはfunction printscript()が引数として与えられる
    def wrapper(*args, **kwargs): # デコレーターの中身、*args, **kwargsはデコレートする関数の引数。幾つあっても大丈夫な書き方。
        print('*'*len("Hello world"))
        func(*args, **kwargs) # 引数として渡された関数(printscript)を実行
        print('*'*len("Hello world"))
    return wrapper

@deco
def printscript():
    print("Hello world")

printscript()

@deco
def forloop():
    for i in [1, 2, 3, 4, 5]:
        print(i)

forloop()

デコレータは同じモノを使っているが、所与のリスト1〜5の数字を順次出力する関数forloop()を追加した。

printscript()は同じ出力だが、forloop()はどの様に出力するだろうか。
一つ一つにデコレートされるのだろうか?

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
% python3 sample1fl.py
***********
Hello world
***********
***********
1
2
3
4
5
***********
% python3 sample1fl.py *********** Hello world *********** *********** 1 2 3 4 5 ***********
% python3 sample1fl.py
***********
Hello world
***********
***********
1
2
3
4
5
***********

最初と最後だけにデコレートした行が追加された。
なる程、decoratorは関数forloop()全体をデコレートすると言う理解。

11/10追記:pythonファイルの実行と出力結果のソースコードについて、Visual Studioでの出力結果を記載していた為にターミナル表記と異なっていた点を修正しました。

コメント

  1. […] Python decoratorの簡単な練習1でやった様にfor loopも測ってみる。5個では少な過ぎるので、100まで(0〜99)の数字で下記のbenchfl.pyを作る。 […]

  2. […] Python decoratorの簡単な練習1 Python decoratorの簡単な練習1 […]

  3. […] Python decoratorの簡単な練習1 […]

タイトルとURLをコピーしました