【初心者向け】わかりやすくPythonのデコレータの基本を解説

Pythonのデコレーター(decorator)の基本的なイメージを初心者向けに解説

今回はPythonの基本文法(?)の中でも初心者や入門者にわかりにくいデコレータについて、その考え方の基本の解説です。イメージをつかんでもらえれば嬉しいです。

(1) デコレータは糖衣構文(シンタックスシュガー:Syntax Sugar)の1種

Pythonのデコレータ(decorator)は、糖衣構文(シンッタクスシュガー)の1種です。

糖衣構文とは、複雑なコードを見やすく、よりシンプルに書けるようにするための構文・文法のことです。

よってPythonのデコレータも、面倒なコードを少し楽にしてくれるお手軽な文法の1つです。

(2) デコレータの機能とは?:関数の一時的な改変・上書き

Pythonにおけるデコレータの機能とは、「すでにある関数を一時的に書き換える・改変する・編集する」ものです。

たとえば、ある製品の販売データについてその売上の総個数を出す関数Aを作ったとします。

しかし、あるとき上司から「明日だけでいいから、個数に加えて全体の平均も出せるようにして」という要望があったとします。(まぁエクセルですぐにできますが・・・)

その場合は、大雑把にわけて

方法1:関数Aそのものをいじって、平均も出せるよう改造する
方法2:平均を出す関数を作って、それと関数Aを上手く組み合わせる

という2つのやり方があると思います。

ですが方法1の場合は、これまで使ってきた関数Aのコード自体をいじることになり、関数Aそのものが変わってしまうため、それを使う全てのプログラムに影響が及びます。下手したらエラーが出るかもしれません。

上司からの要望は「明日だけ」という期間限定なので、そのためだけに関数Aそのものをいじって悪夢に迷い込むのは避けたいところです。

そこで、関数A自体はいじらずに済む方法2を採用したいところです。

そこでPythonのデコレーターが役に立ちます。Pythonのデコレータを使えば、好きなタイミングで、好きな時だけ、既存の関数をいじらずに、その関数の機能を一時的に変更できます。

(3) デコレータの使い方

①基本的な使い方

まず乱暴にではありますが、デコレータの使い方は次のような流れとなります。

・一時的に改造したいなんらかの関数(関数A)があるとする

・デコレータとなる関数を定義する

・デコレータとなる関数内部に、関数Aを改造するための関数(関数B)を定義する

・関数Aに関数Bを適用する

このような流れとなります。

実際にコードとしてよくある典型的・基本的な形式の一例を次に書いておきます。あくまで一例ですが。

#1 デコレータとなる関数Cと、既存の関数Aを改変させる関数Bを定義。関数Bは関数Cの内部にあるため関数内関数と呼ばれる

def 関数C (引数)
    def 関数B ()
        既存の関数を改変する処理
        return 処理結果
    return 関数B

#2 既存の関数Aの定義
def 関数A ()
    処理

#3 関数Aに改変を適用(厳密には違う)
関数A = 関数C (関数A)

#4 改変後の関数Aを実行
関数A ()

このうち、#2~#3の

#2 既存の関数Aの定義
def 関数A ()
    処理

#3 関数Aに改変を適用(厳密には違う)
関数A = 関数C (関数A)

については、次のように書き換えることが可能です。

@関数C #←「関数A = 関数C (関数A)」の代わりの書き方
#2 既存の関数Aの定義
def 関数A ()
    処理

このような@を使った書き方をする場合は、改変される関数の直前に@~を置いてください。この場所を間違うとハマります。

さて、このような書き方をすることで、「一時的に、そのときだけ」関数Aの内容を改変することができます。

では具体例を見てみましょう。

②具体例

以下の例では、@~を使う表記で書いてみました。

今回は、本来ならば「hello」と小文字で表示する関数greetを、デコレータによって、「HELLO」と大文字化させて表示させるように改変するものです。

##############################
#基本1 デコレータ(decorator)
##############################

#1 デコレータとして関数upper_fncを定義
def upper_fnc(func):
    def modify():#関数内関数としてmodifyを定義
        original_result=func()
        modified_result=original_result.upper()
        return modified_result
    return modify #デコレータはmodifyという「関数そのものを返す」


@upper_fnc #これを書く場所に注意。
#2 改変対象となる関数の定義(本来は小文字でhelloと表示される)
def greet():
    return "hello"

#3 上で定義した関数greetのオブジェクトIDを確認
print(id(greet)) #2008200262712(この数字は人によって環境によって変わります)



#4 greetに関数modifyを代入。今回この部分はコメントアウトしているので(@~の書き方をすでに上でつかっているため)動きません
#greet=upper_fnc(greet) 

#5 オブジェクトgreetの型を確認
print(type(greet) ) #<class 'function'>(Jupyternotebook上ではこう表示)

#6 オブジェクトgreetのオブジェクトIDを確認
print(id(greet) ) #2008198589320(#3の数字と違うことに注意しましょう)

#関数そのものではなはく、関数を実行した結果が出力
greet()

③解説

上のコードの一部を再び掲載します。

def upper_fnc(func):
    def modify():
        original_result=func()
        modified_result=original_result.upper()
        return modified_result
    return modify

@upper_fnc
def greet():
    return "hello"

このデコレータの動作の大枠を乱暴にまとめると次のようになります。

・デコレーターとなる関数(ここではupper_fnc)を書く。これの引数funcには、改変したい関数のgreetが代入される。

・改変したい関数(ここではgreet)のすぐ上に「@デコレーターとなる関数の名前(upper_fnc)」と書く。すぐ上に書くからこそ、greetがデコレーターの対象となるとプログラムが判断できます。だから置く場所が重要です。

・関数(ここではgreet)が、デコレーターの内部の関数(ここではmodify)に置き換わる。これはデコレータが関数そのものを返すので、それを受け取り代入された側は関数そのものになります。#5でオブジェクトの型を確認しているのに注目してください。その型は関数です。

以上です。デコレータのイメージをつかめたでしょうか?

③デコレータは実は関数の改変や上書きではない?

さて以上のことでデコレータのだいたいのイメージがつかめれば、あとはデコレータのより発展的な学習を進めていけると思います。

なお上のコードのうち次の部分に着目してください。便宜上、@を使わないバージョンのコードにしています。

#3 上で定義した関数greetのオブジェクトIDを確認
print(id(greet)) #2008200262712(この数字は人によって環境によって変わります)

#4 greetに関数modifyを代入 @upper_fncと書いてもOKだが、その場合は#2の直前に書く
#greet=upper_fnc(greet) 

#6 オブジェクトgreetのオブジェクトIDを確認
print(id(greet) ) #2008198589320(#3の数字と違うことに注意しましょう)

これをみてもらえばわかると思いますが、最初に定義されたgreen(改変前)と、改変後の#6のgreetではオブジェクトIDが異なっていることがわかります。

すなわち、よくデコレータは関数の上書きなどと説明されますが(この記事でもそう書いていますが)、実は、もともとの関数とは異なる新しいオブジェクトを作成し、その新オブジェクトを使って処理を進めているのだとわかります。

「もとの関数をいじらないまま」、とはこういうことなのですね。

以上、Pythonのデコレータのものすごく初歩的で大雑把な説明でしたが、イメージはつかめたでしょうか。

lambda関数などとともに、Python入門者や初心者にはわかりにくいものの1つでしょうが、みなさんの今後の学習の助けになれば幸いです。

(なぜか私のAtom+Hydrogenの環境では、@~の記法だとエラーがでます。Jupyternotebookなどは大丈夫なのに・・・)

やっぱりプログラミングは独学だとわかりにくいですよね、そこでスクールや動画による解説を利用しましょう!

Tech Academy

厚切りジェイソンのCMでおなじみのプログラミングスクール。自宅でオンライン受講OK。現役のプロが一人一人に専属メンターになってくれ、質問すればすぐに回答。転職保証あり

Udemy

世界最大級のオンライン学習動画サービス。AI・データサイエンスなど最先端のプログラミング講座からビジネススキル講座まで10万以上の講座から選び放題。講師に掲示板から直接に質問もできる。