【Python】”@(アットマーク)”から始まる行はどういう意味?【デコレータ】

プログラミングのKnow-howを共有しましょう

【Python】”@(アットマーク)”から始まる行はどういう意味?【デコレータ】

スポンサーリンク

今回はPythonのソースコードでたまに見かける”@(アットマーク)”から始まる文(デコレータ)について、それがどういう意味を持つのかを解説していきます。

Pythonのソースコードを見ている時、たまにこういう記述はないでしょうか?

test()関数の前の行に、「@outputMessage」というよくわからない文がありますね。

これは一体なんなのでしょうか?

@(アットマーク)から始まる行は、デコレータ

このような文のことをデコレータと言います。
デコレートには飾り付ける、修飾するという意味がありますが、Pythonとしてのデコレータもまさにその通り、デコレータの以下の関数をデコレートする機能を持ちます。

このデコレータ、様々なパターンがあって理解するのが難しいです。
今回は一番簡単なパターンを紹介します。

デコレータが1つ、引数なしのテンプレパターン

これが最も簡単なパターンです。この関数を実行すると以下のような結果になります。

デコレータがなければtest関数内で”Hello World”、
メイン関数でtest関数の復帰値である”OK”

のみが出力されるはずですが・・・”Hello World”の間に”start!!”,”end!!”が挟まっていますね。

デコレータを使ってできること

実は@outputMessageがついた状態でtest関数を実行すると、test関数ではなくtest関数を引数としてoutputMessage関数を実行します。

test()関数を引数にするということは・・・?
test()関数を変数として、前後の処理を好きに配置してデコレートできるということじゃありませんか!
つまりoutputMessage関数内では、test関数実行の前後に”start”,”end”を出力するようデコレートしているのです。

これで何ができるのかというと

例えば

  • 関数の処理時間を計算したい場合は、それを出力するデコレータを作成!
  • 関数単位で進捗状況を出力したい場合は、引数の関数名を取得して出力するデコレータを作成!

あとはデコレートしたい関数の上に”@”付きで配置して実行するだけでOK!

なんてことができます。
特に、複数の関数に同じことをしたい場合に大変便利ですね。

さて、もう少し詳しく中身をみていきましょう。

デコレータ関数の中身

outputMessage関数の引数funcはtest関数です。
このoutMessage関数は、wrapperを復帰値として返していますね。

wrapper関数では、”start”,”end”の出力の間にfunc(test)関数を実行、それをresultに入れ、復帰値として返します。
つまり最終的に、outputMessage関数はresult,つまりtest関数の復帰値を返すということです。
test関数の復帰値は”OK”という文字列です。処理の順番をフローにすると

“start”を出力→test関数を実行(“Hello World”を出力)→”end”を出力→test関数の復帰値を受け取ったメイン関数で”OK”を出力

となります。

では、以下の場合はどうなるでしょう?

wrapper関数を無くしてみました。この場合はどのように出力されると思いますか?
ヒントはoutputMessage関数の復帰値です。

正解はこうです。

“OK”が出力されずに、エラーが表示されてしまいました・・・。

outputMessage関数の復帰値を考えてみましょう。

wrapperがあった場合の復帰値は、wrapper関数
wrapperがない場合の復帰値は、result・・・つまり”OK”という文字列

返すものが全く違いますね。メイン関数をみると「print(test())」となっていますが、文字列に「()」はつけませんよね。
逆に「print(test)」なら”OK”が出力されるということです。

test関数はあくまで関数なので、デコレータの復帰値も関数となるように内部関数を定義しましょう。

まとめ

今回はPythonのソースで見かける”@(アットマーク)”から始まる文、デコレータについて紹介しました。

関数の前後に決まった処理をデコレートしたい時があれば、ぜひ使ってみてください。

今回紹介したのはデコレータの一番簡単な例で、他にも

  • デコレータが複数存在する
  • デコレータの引数に関数ではなく*args,**kwargsを指定する

等のパターンもあります。これらについては別の機会に紹介したいと思います。