[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をフォローして頂けると幸いです ^ ^。
最後までご覧頂きましてありがとうございました!