はじめに
Pythonで複数のコンストラクタを定義したい、しかしメソッドのオーバーロードはできないので、一つのクラスは__init__()
メソッドを1つしか持てない、、
そんな場合のベストプラクティスについてstackoverflowに上がっていたので、なるほど、と思った回答2つを備忘録がてら紹介します。
What is a clean, pythonic way to have multiple constructors in Python?
解決したい問題
プロパティnum_holesを持つ、Cheeseクラスを作成する。
コンストラクタには以下の2パターンを用意したい。
- 生成時にnum_holesを明示的に指定する
- 生成時にnum_holesを指定せず、ランダムに設定させる
解決策
※サンプルコードは、元記事のものから適宜改変しています。
① デフォルト値Noneを設定する
class Cheese:
def __init__(self, num_holes=None):
self.num_holes = num_holes if num_holes is None else randint(0, 100)
シンプルな方法です。多くの場合この方法で実装するのではないかと思います。
②コンストラクタをラッパーするclassmethodを定義
class Cheese:
def __init__(self, num_holes=0):
"""defaults to a solid cheese"""
self.number_of_holes = num_holes
@classmethod
def random(cls):
return cls(randint(0, 100))
@classmethod
def slightly_holey(cls):
return cls(randint(0, 33))
@classmethod
def very_holey(cls):
return cls(randint(66, 100))
num_holesの生成方法ごとにclassmethodを定義し、インスタンスを返却する方法です。
サンプルコードのように、指定/ランダムの二択以外にも、複数の設定手段を提供できます。
考えてみれば、組み込みのdatetime
クラスのnow()
とかfromtimestamp()
とかはこのパターンですね。
どっちを使えばいい?
①を使う場合
[値を指定する/指定せずデフォルト値を指定させる]の2択で済む場合はこちらですね。
やはりコンストラクタのみで完結するので直感的であり、今回の問題においては最適解だと思います。
stackoverflowでもこちらの回答がbest answerとなっています。
②を使う場合
[値を指定する/指定せずデフォルト値を指定させる]以上の分岐が必要になる場合は②も選択肢となります。
サンプルコードのように、デフォルト値は固定値として、それとは別にランダム生成の手段も提供したい、などの場合です。
これを__init__()
で完結させた場合に、余計な引数を追加する必要があったり、処理が複雑になったりするようだったら②の方法での実装も考えるべきですが、コンストラクタ以外でのインスタンス生成するのは若干直感的じゃないというか、嫌いな人は嫌いそうではあります。