【Python初心者のための便利なデコレータ解説 #3】クラス全体に使える？@classmethod の使い方と考え方をやさしく解説！

## はじめに

このシリーズでは、Python 初心者にもわかりやすく「便利なデコレータ」の使い方を毎回1つずつ紹介していきます。

💡「そもそもデコレータって何？」という方は、まず以下の記事をご覧ください：
> 👉 [【Python初心者のための便利なデコレータ解説 #0】そもそもデコレータってなに？仕組みと使い方をやさしく解説！](https://qiita.com/ys-B/items/d53f2a91c75b8e5981a2)

---

今回は、クラスの中で使えるデコレータのひとつ **`@classmethod`** を紹介します。

このデコレータを使うと、**クラス全体に関係する処理を、インスタンスを作らずに呼び出すことができる**ようになります。

この記事では、`@classmethod` の使い方やメリットを、具体例を交えながらわかりやすく解説していきます。

---

## Pythonクラスのメソッドと self のまとめ
`@classmethod` の説明に入る前に、Python のクラスでよく見るキーワード `self` について先に整理しておきましょう。
これが理解できていないと、`@classmethod` が難しくなってしまいます。

🔰 `self` って結局なに？
`self` は **「今使ってるそのオブジェクト自身」** を意味する特別なキーワードです。
Python のクラスの中で定義されたメソッド（関数）は、 **「どのインスタンス（オブジェクト）の話なのか」** を知る必要があります。そのときに使われるのが `self` です。

> **「私の名前はポチです」** というワンちゃんがいたら、
> self.name の self は「私（＝そのワンちゃん）」のこと。

🐶 具体的な例でイメージしてみよう

例：`self` を使ったクラス
```Python
class Dog:
    def __init__(self, name):
        self.name = name

    def bark(self):
        print(f"{self.name}がワンワン！")


dog = Dog("ポチ")
dog.bark()  # → ポチがワンワン！
```
-  `dog = Dog("ポチ")` で、「ポチ」という名前を持つ Dog オブジェクトを作ります
-  `dog.bark()` を呼ぶとき、Python は自動的に dog 自身を self に渡してくれます

つまり、実際にはこう動いているのと同じです：
```Python
Dog.bark(dog)
```
これを見るとわかるように、`dog` というインスタンス自身が引数として渡されることで、`self` の中身が決まります。

つまり、`self` は「今、誰がこのメソッドを呼んでいるか？」をPythonに伝えるための引数なんです。

だから、このような形で`self` をメソッドの最初の引数として書いておく必要があるんですね。
```Python
def bark(self):
    print(f"{self.name}がワンワン！")
```
### 🔁 `self.method()` って書き方見るけど、それってどういう意味？
例えばこんなクラスがあったとします。
```Python
class Dog:
    def __init__(self, name):
        self.name = name

    def introduce(self):
        print(f"ぼくの名前は {self.name} です！")
        self.bark()

    def bark(self):
        print("ワンワン！")


dog = Dog("ポチ")
dog.introduce()
```
出力
```Python
ぼくの名前は ポチ です！
ワンワン！
```
この`self.dark()`は、 **「今動いている自分（インスタンス）が持っているメソッド bark を呼び出す」** という意味です。
`introduce` メソッドの中で「同じインスタンスの他のメソッド」を呼び出しているからです。

> self を通じて、自分自身が持っている属性やメソッドにアクセスする、というのがPythonのルールです。

### ✨ まとめ
- `self` は「どのインスタンスが呼び出したか？」を伝えるために必要
- メソッドの中で `self.method()` と書くのは、「自分自身の別の機能を使う」ため
- Pythonでは、インスタンスメソッドを書くときには、最初の引数に `self` を 明示的に 書くというルール

## 🤔 `self` は必ず必要なの？ 〜 すべてのメソッドに `self` がいるわけじゃない！？ 〜
ここまで読んだ人は、もしかするとこう思ったかもしれません。

> 「クラスの中のメソッドって、全部 `self` 書かなきゃいけないの？」
> 「`self` を使わないメソッドってアリなの？」
> 「自分自身の状態を使わないなら、いらないのでは？」

はい！その通りです！
`self` を使わないメソッドも Python クラスの中で書けますし、それ専用の書き方もちゃんと用意されています。
`staticmethod`と呼ばれています。詳しく知りたい方は以下の記事を読んでみてください！
> 👉 [Python初心者のための便利なデコレータ解説 #2】 インスタンスなしで関数を呼べる！？ @staticmethod の使いどころを解説！](https://qiita.com/ys-B/items/1e2c36e17efb46558797)

## `@classmethod` とは？
ここからは今回の主役 **`@classmethod`** の出番です。

これはその名の通り、 **「クラス（class）自身に対して動くメソッド」** を作るためのデコレータです。

`self` が「オブジェクト自身（インスタンス）」を表していたのに対して、  
`@classmethod` では最初の引数に `cls` を使うことで、 **「クラスそのもの」** にアクセスできます。

たとえばこんなときに役立ちます：

- インスタンスを作らずに、クラスに関する処理をしたいとき  
- クラス変数（全体で共有される値）にアクセスしたいとき  
- インスタンスの別の作り方（ファクトリメソッド）を提供したいとき

> 💡 `cls` は “class” の略。`self` のクラスバージョンと考えると理解しやすいです。

このあとは、具体的なコード例を見ながら `@classmethod` がどんなふうに使えるのか、見ていきましょう！

## 🔧 `@classmethod` の具体例1：クラス全体の設定を変える
```Python
class Student:
    school_name = "サンプル学園"  # クラス変数（全員共通）

    def __init__(self, name):
        self.name = name  # インスタンス変数（個人ごと）

    def introduce(self):
        # self を使ってインスタンスの情報にアクセス
        print(f"私は {self.name} です。{self.school_name} に通っています。")

    @classmethod
    def change_school(cls, new_name):
        # cls を使ってクラス変数を変更
        cls.school_name = new_name
```
使い方
```Python
# インスタンスを2人作る
s1 = Student("アリス")
s2 = Student("ボブ")

s1.introduce()  # → 私は アリス です。サンプル学園 に通っています。
s2.introduce()  # → 私は ボブ です。サンプル学園 に通っています。

# クラスメソッドを使って学校名を変更
Student.change_school("ニューサンプル高校")

s1.introduce()  # → 私は アリス です。ニューサンプル高校 に通っています。
s2.introduce()  # → 私は ボブ です。ニューサンプル高校 に通っています。
```

### ✅ ポイント
- `introduce()` は個々のインスタンスの状態にアクセス → `self` を使う
- `change_school()` はクラス全体の設定を変更 → `cls` を使ってクラス変数にアクセスできる
- インスタンスを作らなくても呼び出せるのが便利！


## 🔧 `@classmethod` の具体例2：継承先でも正しく動く汎用メソッド
継承したサブクラスに応じて、クラス変数をうまく使い分けたいときにも `@classmethod` は便利です。

🧪 例：文字列からインスタンスを作る
```Python
class Animal:
    species = "不明"

    @classmethod
    def describe(cls):
        print(f"この動物は {cls.species} です。")

class Cat(Animal):
    species = "ネコ"

class Dog(Animal):
    species = "イヌ"

Cat.describe()  # → この動物は ネコ です。
Dog.describe()  # → この動物は イヌ です。
```
### ✅ ポイント
- `cls` は呼び出し元のクラスを自動で指すので、サブクラスに応じて動作が変わる

## 🔧 `@classmethod` の具体例3：共通の状態を管理する（例：インスタンス生成回数）
インスタンスが何回作られたかなど、クラス全体で管理したい情報にも `@classmethod` がぴったりです。

```Python
class Counter:
    count = 0

    def __init__(self):
        Counter.count += 1

    @classmethod
    def get_count(cls):
        return cls.count
```
```Python
c1 = Counter()
c2 = Counter()

print(Counter.get_count())  # → 2
```
### ✅ ポイント
- 全インスタンス共通の情報（count）をクラスレベルで保持
- 集計・統計・ロギング的な処理に便利！

## 🧩 `self` と `cls`、それぞれの“便利ポイント”をまとめよう！
| 種類             | 最初の引数  | アクセスできるもの                   | 主な用途               | 💡便利なポイント                   |
| -------------- | ------ | --------------------------- | ------------------ | --------------------------- |
| **インスタンスメソッド** | `self` | インスタンス変数（`self.name` など）    | 個別の状態やふるまいの定義      | インスタンスごとに異なる動作ができる          |
| **クラスメソッド**    | `cls`  | クラス変数（`cls.school_name` など） | クラス全体に関わる処理・設定管理など | インスタンスなしで使える／継承先でも自動的に対応できる |


## ✅ まとめ
- `@classmethod` は インスタンスを作らずにクラスにアクセスできる のが最大の強み
- 共通設定の変更・継承対応・状態管理など、「クラスというまとまり」を扱う処理に最適
- インスタンスを使わない＝シンプルな設計ができる

## 終わりに
クラスを設計していると「インスタンスには関係ないけど、クラス全体として扱いたい処理」が意外とよく出てきます。そんなときに役立つのが `@classmethod` です。
インスタンスを作らずに呼び出せて、共通設定や状態の管理、継承にも柔軟に対応できるのが魅力です！ぜひ意識して`@classmethod`を書いてみてください！