こんにちは。外は珍しく大雨で、朝からなかなか降りやみません。もともと外出自粛していましたが、こんな時は家に籠るに限ります(最近は籠ってばかり)。
本投稿では、Pythonプログラミングをする上で有用ですがなかなか使いこなせないデコレータについて説明したいと思います。私も勉強中の身ではありますが、3分で理解できるデコレータの説明を目指して文書を描きました。
なお、この記事では
ラッパー
呼び出し可能オブジェクト
糖衣構文(シンタックスシュガー)
などの難しい単語は使いません。IT系の専門技術の解説では、知らない技術の解説の中にさらに知らない技術や単語が出てきて混乱するということが良くあると思います。なので余計な専門用語はここでは省いています。また、執筆にあたり以下の本を参考にしました。最近出版されたばかりのPython中級者向けのテクニック集で、明日から使ってみたい技術が詰まっています。
- 作者:Dan Bader
- 発売日: 2020/04/15
- メディア: 単行本(ソフトカバー)
1.そもそもデコレータってなぁに?
デコレータとは、Pythonにより実装されている既存の関数に、別の機能を付加させるための装置のことを言います。多くの場合メソッド名の上に@デコレータ名を付けて使用を宣言します。以下は簡単な例ですが、入力したテキストにデコレータを使って適当な語尾を付けています。このような書き方はテンプレなので覚えておきましょう。
#デコレータとなる関数を自由に設計。文字列末尾に'たぬ'を付けたい。 def add_tanu(func): def wrapper(text): original = func(text) result = original + 'たぬ' #ここで目的となる機能が追加される。 return result return wrapper #狸がtextを話すメソッド。textで指定した文字列がそのまま返される。 @add_tanu def tanuki_speak(text): return text tanuki_speak('ご飯') #デコレータで修飾したことで語尾に'たぬ'が付き、'ご飯たぬ'が返ってくる。 #ご飯たぬ
2.自作しなくちゃいけないの?
上の例のように自由に作ることもできますし、Pythonに標準で搭載されているデコレータも存在します。例えば以下のようなデコレータが最も一般的だと思われます。これらはライブラリをインポートせずとも、直書きできます。
- @staticmethod
- @classmethod
- @property
また、ライブラリをインポートして使うデコレータもあります。以下のようなabcモジュールは有名ライブラリのソースコードを読んでいるとたまに見かけます。
from abc import ABCMeta, abstractmethod class BaseClass(metaclass = ABCMeta): @abstractmethod def tanuki(self): pass
もちろん、デコレータは機能をよく理解した上で使用する必要があります(語尾に'たぬ'がつくような簡単な機能だったら良かったのですが、これらのデコレータはもうちょっと複雑です)。気になるデコレータがあったら公式マニュアルを参照しましょう。
3.なんのために使うの?
語尾に'たぬ'を付ける例を見てこう思われたかもしれません。デコレータで修飾されている関数内で、text + 'たぬ'とでもすればいいんじゃない?と。それは間違いなく正しいです。デコレータが真価を発揮するのは、以下のような場面かと思います。
- 修正したいメソッドが大量にある
上の例ではtanuki_speakを修正するだけでした。しかし修正すべきメソッドが大量にあった場合はどうでしょう?メソッド自体を書き換える手間よりも、デコレータを1つ自作して@デコレータを張り付けた方がはるかに楽ではないでしょうか。
- 誤作動の少ない強固なプログラムにする
上で@staticmethod 、@classmethod、abcモジュールに触れましたが、これらはプログラムの誤作動を減らすために使えます。
例として、発展的な話を一つだけ(3分経ったので読み飛ばしても大丈夫です!)。@staticmethodがクラス内のメソッドの前に置かれた場合、そのメソッドは静的メソッドと呼ばれます。普通のクラス内メソッド(インスタンスメソッド)はselfパラメータに自由にアクセスできますが、静的メソッドではそのアクセスを禁止します。このようにメソッドの機能をわざと制限することにより、誤ってパラメータを上書きしてしまうといったリスクを低減することができます。複数人で開発を行ったり長期間運用するような大規模プロジェクトでは欠かせない機能です。
class Myclass: def __init__(self): self.param = tanuki @staticmethod def static_tanuki(): return self.tanuki #static_tanukiはself.tanukiにアクセスできないためこれはエラーをはく
最後は難しい話題になってしまいましたが、上記プログラムの保守性や堅牢性が求められる場面でなければ強いて使う必要はないかなとは思います(なくても動きますから・・・)。しかし、キャッシュ機能がありプログラムを高速化させるなどの便利デコレータも多数存在します。また人のコードをスラスラ読んだり、パイソニスタとしての腕を上げたいのであればデコレータは避けて通れないでしょう!私ももっと勉強しないとなぁ。