[Python] デコレーターに入門する
こんにちは、@yoheiMuneです。
Pythonのコードで時々ある
このブログでは、デコレータの定義方法や使い方を書きたいと思います。
また、以下のデコレーターのように付与対象の関数の結果を変化させることもできます。
『入門 Python 3(O'Reilly)』
最後になりますが本ブログでは、Python・Swift・Java・フロントエンド・機械学習など雑多に情報発信をしていきます。自分の第2の脳にすべく、情報をブログに貯めています。気になった方は、本ブログのRSSやTwitterをフォローして頂けると幸いです ^ ^。
最後までご覧頂きましてありがとうございました!
Pythonのコードで時々ある
@xxxというアノテーションがついた関数がありますが、そのアノテーションをデコレータと言います。今日はその使い方や定義方法などブログに書きたいと思います。
目次
デコレーターとは
デコレーターとは、以下のように関数に@xxxをつけるものを指します。
@document_it
def add_ints(a, b):
return a + b
上記の@document_itがデコレータで、これを付与することでadd_ints関数の中身を変えずして振る舞いを変えることができます。FlaskなどのWebアプリケーションでは、@app.route('/')などでルーティングにもちいられています。このブログでは、デコレータの定義方法や使い方を書きたいと思います。
デコレーターを定義する
デコレーターに利用する関数は、以下のように定義することができます。
# デコレーター用の関数
# 引数に、デコレータ対象の関数を受け取る
def document_it(func):
"""デコレータ対象の関数について、関数名 / 引数の内容 / 実行結果を表示する"""
def new_function(*args, **kwargs):
# デコレータ付与先の関数名
print("Runnning function:", func.__name__)
# デコレータ付与先の関数が受け取る位置引数の一覧
print("Positional arguments:", args)
# デコレータ付与先の関数が受け取るキーワード引数の一覧
print("Keyword arguments:", kwargs)
# 実行する
result = func(*args, **kwargs)
# デコレータ付与先の関数の結果を表示する
print("Result:", result)
# デコレータ付与先の関数の結果を返却する
return result
return new_function
そして、上記の関数を以下のようにデコレーターとして設定します。
@document_it
def add_ints(a, b):
return a + b
これで、デコレーターの設定は完了です。実際に動かしてみると、以下のように表示されます。
>>> add_ints(1, 2)
Runnning function: add_ints
Positional arguments: (1, 2)
Keyword arguments: {}
Result: 3
3
このように関数の中身を変えずに、処理を追加/変更できるのがデコレーターの特徴です。なかなか便利ですね!また、以下のデコレーターのように付与対象の関数の結果を変化させることもできます。
# デコレート対象の関数の結果を二乗する
def square_it(func):
def square_it_new_function(*args, **kwargs):
result = func(*args, **kwargs)
return result * result
return square_it_new_function
@square_it
def add_ints(a, b):
return a + b
# 実行結果が二乗される
add_ints(1, 2) # 9
複数のデコレーターを付与した場合の実行順序
デコレーターは複数付与することもできます。その場合には、関数に最も近いデコレーターから実行されます。
# 実行順を見える化するために、printを各所に追加
def document_it(func):
def new_function(*args, **kwargs):
print("document_it starts")
print("Runnning function:", func.__name__)
print("Positional arguments:", args)
print("Keyword arguments:", kwargs)
result = func(*args, **kwargs)
print("Result:", result)
print("document_it ends")
return result
return new_function
# 同じく、printを追加
def square_it(func):
# 関数名もdocument_itを変えています
def square_it_new_function(*args, **kwargs):
print("square_it starts")
result = func(*args, **kwargs)
print("square_it ends")
return result * result
return new_function
# デコレーターを2つ付与
@document_it
@square_it
def add_ints(a, b):
return a + b
# 実行した結果は以下の通り
add_ints(1, 2)
"""
document_it starts
# document_itが受け取る関数は、square_it_new_functionとなっている
Runnning function: square_it_new_function
Positional arguments: (1, 2)
Keyword arguments: {}
# 関数の処理としては、squre_itから実行される
square_it starts
square_it ends
Result: 9
document_it ends
9
"""
# デコレーターを逆順にしてみると、実行順序が変わる
@square_it
@document_it
def add_ints(a, b):
return a + b
# 実行した結果は、以下
add_ints(1, 2)
"""
square_it starts
document_it starts
# 今回の場合は、document_itデコレーターはadd_intsを関数として受け取っている
Runnning function: add_ints
Positional arguments: (1, 2)
Keyword arguments: {}
Result: 3
document_it ends
square_it ends
9
"""
このように、複数のデコレーターを付与した場合には、関数に近い順から実行されます。参考資料
Pythonの基礎勉強は、以下の書籍を熟読して猛威勉強中です。色々と掲載されていて非常に参考になります。『入門 Python 3(O'Reilly)』
最後に
今日はPythonの@xxxであるデコレーターをブログで扱いました。Pythonで最初にこれを見たときに、なんだろうこれと思っていたのを思い出しますw。関数の中身を変えずして振る舞いを変えられるのは、なかなか素敵ですね♩最後になりますが本ブログでは、Python・Swift・Java・フロントエンド・機械学習など雑多に情報発信をしていきます。自分の第2の脳にすべく、情報をブログに貯めています。気になった方は、本ブログのRSSやTwitterをフォローして頂けると幸いです ^ ^。
最後までご覧頂きましてありがとうございました!






