はじめに
Java系のプログラムを長い期間にわたって書いた後、Java系でない他のプログラミング言語でプログラムを書き始めてちょっとした難問に出くわすと、ついJava系では簡単にできていたはずの書き方を試してみたくなることがあります。
そんな中、Python3でコンストラクタをオーバーロードしないと困ったことになりそうな局面に遭遇しました。
幸いなことにコンストラクタをオーバーロードしなくてもよくなる設計にできる見込みとはなりましたが、Java系では簡単にできていたコンストラクタをオーバーロードがPython3でもできるかもしれないという点についてはちょっと興味が湧いたので、Python3でコンストラクタのオーバーロードのようなコードを書くための方法について調べてみて、可能そうであれば試してみることにしました。
いきなりコード例
少し調べてみると、Python3には「classmethodデコレータ」なるものがあることがわかりました。
Python3でコンストラクタのオーバーロードのようなコードを書くことができそうです。
そこで、以下のようなプログラム(というかクラスの定義)を書いてみました。
Expenseクラスです。
Expenseクラスのインスタンスは1回の費用を表していて、支出は、
- 金額(amount)
- 目的(reason)
- 備考(remark)
の3個の項目から構成されています。
このExpenseインスタンスはPythonでは一般的に使われているコンストラクタ(__init__, 7-10行目, 3個の引数をとるコンストラクタです。)の他に、classmethodデコレータを用いて以下の2個のコンストラクタ(のように動作するクラスメソッド)を定義しています。
- no_remark(12-14行目): amount及びremarkのみを引数としてとるコンストラクタ。
- copy(16-18行目): Expenseインスタンスを引数としてとるコンストラクタ(いわゆるコピーコンストラクタ)
Javaの世界では先頭に”@”のタグのついたコメントのようなものは「アノテーション」といいますが、Pythonの世界では先頭に”@”のタグのついたコメントのようなものは「デコレータ」というようです。
紛らわしいですね。
動作確認
スポンサーリンク
Python3のCLIに前節に示したExpenseクラスをimportして動作確認です。
__init__
まずは__init__関数について動作確認します。
Python3のコンストラクタとしての極めて一般的な動作です。
no_remark
二つ目はno_remark関数です。
no_remark関数は以下のように書きます。
クラスメソッドはインスタンスを作ることなく、クラスから直接呼び出すことができます。
実行してみます。
reasonの値を持たないExpenseインスタンスが作成できることが確認できました。
copy
三つ目はcopy関数です。
copy関数は以下の2行目のように書いて実行します(1行目はコピー元のインスタンスを作成するコードです)。
cc = Expense.copy(c)
実行してみます。
インスタンスcc(コピー先)がインスタンスc(コピー元)をコピーすることにより生成されたことを確認後、cのremarkを”informatics”に変更した後もccのremarkが”electronics”のままで変化していないことを確認しています。
ここまでの確認結果より、copy関数が深いコピー(deepcopy)を行うことができる関数であることがわかります。
まとめ
ここまでの実験で、コンストラクタをオーバーロードする場合にはクラスメソッドを使用する必要があることがわかりました。
また、クラスメソッドとするからには、メソッド名については相異なるものを定義する必要があることになります。
その一方で、クラスメソッドの命名や運用の方針をうまく決めてやると面白い使い方を編み出すことができるのかもしれません。
この記事は以上です。