【Python】クラスメソッドとは?@classmethodの使いどころをインスタンスメソッドと比較して解説

こんにちは。ゆうせいです。

Pythonでオブジェクト指向プログラミングを学び始めると、「クラス」や「インスタンス」、「メソッド」といった概念が登場しますよね。そして、メソッドの定義の上に、時々 @classmethod という不思議な記述を見かけることはありませんか?

「これは一体何のおまじない…?」

「普通のメソッドと何が違うんだろう?」

そんな疑問を抱える新人エンジニアの方に向けて、今回は @classmethod の正体と、そのスマートな使いどころを、基本となるインスタンスメソッドと比較しながら徹底的に解説していきます!


クラスに存在する3種類のメソッド

Pythonのクラスには、実は3種類のメソッドが存在します。それぞれの役割を簡単に見てみましょう。

  1. インスタンスメソッド: 最も標準的なメソッド。インスタンス(モノ)に紐づく操作を行います。
  2. クラスメソッド: 今回の主役。クラス全体に紐づく操作を行います。
  3. スタティックメソッド: クラスに属しているだけの、独立した関数のようなメソッド。

今日は、この中でも特に重要な「インスタンスメソッド」と「クラスメソッド」の違いに焦点を当てて、その謎を解き明かしていきます。


基本の「インスタンスメソッド」を再確認しよう

まず、私たちが普段クラスの中で最もよく書くであろう「インスタンスメソッド」からおさらいしましょう。

インスタンスメソッドは、__init__ で作成したインスタンス(オブジェクト)のデータを使って何か処理を行うためのものです。必ず第一引数に self を受け取りますよね。この self こそが、作られたインスタンス自身を指し示す代名詞です。

例えるなら、Car という「設計図(クラス)」から my_car という「具体的な一台の車(インスタンス)」を作ったとします。その my_car の色を調べたり、エンジンをかけたりする操作がインスタンスメソッドです。その操作は、必ず「どの車に対して行うか」が重要になります。

class Car:
    def __init__(self, make, model):
        # self.makeなどはインスタンスが持つデータ
        self.make = make
        self.model = model

    # selfを受け取るのがインスタンスメソッド
    def display_info(self):
        print(f"この車は {self.make} の {self.model} です。")

# インスタンスを作成
prius = Car("Toyota", "Prius")
tesla = Car("Tesla", "Model 3")

# インスタンスからメソッドを呼び出す
prius.display_info() # この車は Toyota の Prius です。
tesla.display_info() # この車は Tesla の Model 3 です。

display_info メソッドは、prius という具体的なインスタンスのデータを使っているので、インスタンスメソッドなのです。


本日の主役「クラスメソッド」とは?

さて、いよいよクラスメソッドの登場です。

クラスメソッドは、メソッドの上に @classmethod という「デコレータ」を付けて定義します。

インスタンスメソッドが self を第一引数に取るのに対し、クラスメソッドは cls を第一引数に取ります。この cls は、インスタンス自身ではなく、「クラスそのもの」を指し示す代名詞です。

先ほどの車の例で言うなら、「個別の車(インスタンス)」に関する操作ではなく、「Carという設計図(クラス)」自体に関する操作を行うのがクラスメソッドの役割です。例えば、「これまで全部で何台の車が作られたか」をクラスで管理したり、「特定のフォーマットの文字列から新しい車インスタンスを作る」といった操作です。

最大の使いどころ: 代替コンストラクタ

クラスメソッドが最も輝く場面、それは「代替コンストラクタ」としての役割です。

コンストラクタとは、__init__ のようにインスタンスを初期化して作り出す仕組みのこと。Car("Toyota", "Prius") のように普通に作る以外の方法で、インスタンスを作るための特別な入り口を用意したい時に、クラスメソッドが非常に役立ちます。

例えば、"Toyota-Prius" のようなハイフン区切りの文字列から Car インスタンスを作りたい、というケースを考えてみましょう。

class Car:
    num_cars = 0 # クラス全体で共有する変数(クラス変数)

    def __init__(self, make, model):
        self.make = make
        self.model = model
        Car.num_cars += 1

    def display_info(self):
        print(f"この車は {self.make} の {self.model} です。")

    @classmethod
    def get_total_cars(cls):
        # clsはCarクラスを指す
        print(f"生産された車の総数は {cls.num_cars} 台です。")

    @classmethod
    def from_string(cls, car_string):
        # clsを使って新しいインスタンスを生成して返す
        make, model = car_string.split('-')
        return cls(make, model)

# 普通にインスタンス化
prius = Car("Toyota", "Prius")

# クラスメソッドをクラスから直接呼び出す
# 文字列から新しいインスタンスを作る
leaf = Car.from_string("Nissan-Leaf")

prius.display_info()
leaf.display_info()

# 作成された総数を確認
Car.get_total_cars() # 生産された車の総数は 2 台です。

from_string メソッドに注目してください! cls(make, model) という部分で、Car(make, model) と同じように新しいインスタンスを作って返していますよね。clsCar クラスそのものを指しているので、こんなことができるのです。

このように、様々なデータ形式(辞書、JSON、文字列など)からインスタンスを生成するための専用の入り口として、クラスメソッドは最高のツールなのです!


一目でわかる比較表

インスタンスメソッドとクラスメソッドの違いを、表で整理してみましょう。

項目インスタンスメソッドクラスメソッド
デコレータなし@classmethod
第一引数self (インスタンス自身)cls (クラス自身)
呼び出し方インスタンス.メソッド()クラス.メソッド()
主な役割インスタンスのデータを使った操作クラス全体のデータを扱う操作、代替コンストラクタ

今後の学習に向けて

今回は、@classmethod の謎に迫りました。

  • インスタンスメソッドは、個々のインスタンスに対する操作。
  • クラスメソッドは、クラス全体に対する操作や、便利なインスタンス生成工場。

最初は、ほとんどのメソッドをインスタンスメソッドとして書くことになるでしょう。それで全く問題ありません。ですが、もしあなたが「__init__ 以外にも、こういうデータからインスタンスを作れたら便利だな」と感じた時、それは @classmethod の出番です!

この使い分けができるようになると、クラス設計の幅がぐっと広がり、より柔軟で読みやすいコードが書けるようになります。ぜひ、あなたが使っているライブラリのコードなども覗いて、プロの開発者たちがどのように @classmethod を活用しているか観察してみてくださいね。

セイ・コンサルティング・グループの新人エンジニア研修のメニューへのリンク

投稿者プロフィール

山崎講師
山崎講師代表取締役
セイ・コンサルティング・グループ株式会社代表取締役。
岐阜県出身。
2000年創業、2004年会社設立。
IT企業向け人材育成研修歴業界歴20年以上。
すべての無駄を省いた費用対効果の高い「筋肉質」な研修を提供します!
この記事に間違い等ありましたらぜひお知らせください。