今日は @classmethod
と @staticmethod
の使い分け方が話題になりました。私はなんとなく「コンストラクタが複数ある場合は @classmethod
を使う」ようにしています。ただ、他の使い道も自分が知らないだけであるんじゃないかと思い、少し調べてみました。
複数の初期化処理を切り分ける(Factory Methodパターン)
こちらの記事にある通りです。
よく使われる例としては、そのクラスを作るメソッドを書くことです。 以下の例ではクラス Item と、Itemの情報をあるAPIから取得して返す retrieve_from_api というクラスメソッドを実装しています。
class Item: def __init__(self, id, name): self.id = id self.name = name @classmethod def retrieve_from_api(cls, id): res = requests.get(f"https://api.example.com/items/{id}") data = res.json() return cls(id, data["name"])
これはFactory Methodパターンと呼ばれるデザインパターンです。
インスタンス間で共通の変数を保持する
やや古い記事なので、Python2系の xrange
が使われていて少し懐かしいですね。
class Shape: collection = set() def __init__(self,x, y): self.x = x self.y = y def update(self): self.x += 1 self.y += 1 @classmethod def add_new_shape(cls, (x, y)): shape = Shape(x, y) Shape.collection.add(shape) @classmethod def update_all(cls): for shape in Shape.collection: shape.update() def main(): for p in xrange(10): Shape.add_new_shape((p, p)) q = 0 while q < 60: Shape.update_all() q += 1 if __name__ == "__main__": main()
(おまけ)@staticmethodの使いどころ
また、 @staticmethod
は「関数をまとめたクラスオブジェクト(モジュール)を作る場合」に使っています。ただ、Pythonだとファイル単位でモジュールができるので、個人的にはあまり必要性を感じたことがないです。
あとはインスタンス変数やインスタンスメソッドにアクセスしないときにも @staticmethod
を使いますが、個人的な経験では、結局後で他のメソッドを呼ぶことになって self
を書き足すことが多かったのであまりメリットは感じません。
こちらの例は鮮やかですが、なかなかこういう機会はなさそう。