【Python】クラスメソッドとは?@classmethodの使いどころをインスタンスメソッドと比較して解説
こんにちは。ゆうせいです。
Pythonでオブジェクト指向プログラミングを学び始めると、「クラス」や「インスタンス」、「メソッド」といった概念が登場しますよね。そして、メソッドの定義の上に、時々 @classmethod
という不思議な記述を見かけることはありませんか?
「これは一体何のおまじない…?」
「普通のメソッドと何が違うんだろう?」
そんな疑問を抱える新人エンジニアの方に向けて、今回は @classmethod
の正体と、そのスマートな使いどころを、基本となるインスタンスメソッドと比較しながら徹底的に解説していきます!
クラスに存在する3種類のメソッド
Pythonのクラスには、実は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)
と同じように新しいインスタンスを作って返していますよね。cls
が Car
クラスそのものを指しているので、こんなことができるのです。
このように、様々なデータ形式(辞書、JSON、文字列など)からインスタンスを生成するための専用の入り口として、クラスメソッドは最高のツールなのです!
一目でわかる比較表
インスタンスメソッドとクラスメソッドの違いを、表で整理してみましょう。
項目 | インスタンスメソッド | クラスメソッド |
デコレータ | なし | @classmethod |
第一引数 | self (インスタンス自身) | cls (クラス自身) |
呼び出し方 | インスタンス.メソッド() | クラス.メソッド() |
主な役割 | インスタンスのデータを使った操作 | クラス全体のデータを扱う操作、代替コンストラクタ |
今後の学習に向けて
今回は、@classmethod
の謎に迫りました。
- インスタンスメソッドは、個々のインスタンスに対する操作。
- クラスメソッドは、クラス全体に対する操作や、便利なインスタンス生成工場。
最初は、ほとんどのメソッドをインスタンスメソッドとして書くことになるでしょう。それで全く問題ありません。ですが、もしあなたが「__init__
以外にも、こういうデータからインスタンスを作れたら便利だな」と感じた時、それは @classmethod
の出番です!
この使い分けができるようになると、クラス設計の幅がぐっと広がり、より柔軟で読みやすいコードが書けるようになります。ぜひ、あなたが使っているライブラリのコードなども覗いて、プロの開発者たちがどのように @classmethod
を活用しているか観察してみてくださいね。