閉じる

【Python】クラス変数 vs インスタンス変数の違いと使い分けを解説

Pythonでのオブジェクト指向プログラミングでは、クラス変数とインスタンス変数の違いを正しく理解することがとても重要です。

何となく使っていると、値が思わぬタイミングで書き換わったり、インスタンス間でデータが共有されてしまったりというバグにつながります。

本記事では、クラス変数とインスタンス変数の違いと使い分け方を、図解とコード例を交えながら丁寧に解説していきます。

クラス変数とインスタンス変数とは

クラス変数とは

クラス変数とは、クラスそのものに属する変数のことです。

インスタンスではなくクラスに紐づくため、そのクラスから生成されたすべてのインスタンスで共有されます。

Pythonでは、クラス定義の直下(メソッドの外側)に代入することで定義します。

クラス変数のイメージとしては、「設計図レベルで共有される情報」です。

同じクラスから生まれたインスタンスであれば、基本的には同じ値を参照することになります。

インスタンス変数とは

インスタンス変数とは、インスタンス(オブジェクト)ごとに持つ変数です。

各インスタンスごとに別々の値を保存したいときに利用します。

Pythonでは、主に__init__メソッドの中でself.xxxという形で代入することで定義します。

インスタンス変数は、「作られた個々のオブジェクトが持つ固有の情報」です。

同じクラスから作られたインスタンスでも、インスタンス変数の値はそれぞれ異なってかまいません。

Pythonにおけるクラス変数とインスタンス変数の定義方法

クラス変数とインスタンス変数は、定義位置と書き方が異なります。

代表的な例を見てみます。

Python
class User:
    # これはクラス変数 (すべてのUserインスタンスで共有)
    user_count = 0

    def __init__(self, name):
        # これはインスタンス変数 (インスタンスごとに異なる)
        self.name = name

        # クラス変数を更新
        User.user_count += 1


# インスタンスの生成
u1 = User("Alice")
u2 = User("Bob")

# クラス変数へのアクセス
print(User.user_count)  # 2

# インスタンス変数へのアクセス
print(u1.name)  # Alice
print(u2.name)  # Bob
実行結果
2
Alice
Bob

このように、クラス変数はクラス直下に、インスタンス変数はself.変数名としてメソッド内に書くことで明確に区別します。

クラス変数の特徴と使い方

クラス変数の参照と更新の挙動

クラス変数は、クラスとインスタンスの両方から参照できますが、どのように更新するかによって挙動が変わるため注意が必要です。

Python
class Counter:
    # クラス変数
    count = 0

    def __init__(self):
        # コンストラクタが呼ばれるたびにクラス変数を1増やす
        Counter.count += 1


c1 = Counter()
c2 = Counter()

# クラスから参照
print(Counter.count)  # 2

# インスタンスからも参照可能 (内部的にはクラス変数を見に行く)
print(c1.count)  # 2
print(c2.count)  # 2

# クラスから更新
Counter.count = 10
print(c1.count)  # 10
print(c2.count)  # 10

# インスタンスから「代入」するとどうなるか
c1.count = 99
print(c1.count)      # 99 (インスタンス変数として新しく作られる)
print(c2.count)      # 10 (クラス変数のまま)
print(Counter.count) # 10
実行結果
2
2
2
10
10
99
10
10

この例から分かるように、クラス変数を更新したいときはクラスから代入することが重要です。

インスタンスからc1.count = 99のように代入すると、クラス変数を書き換えるのではなく、そのインスタンス専用の同名インスタンス変数を新しく作ってしまうため、意図しない状態を招きます。

クラス変数が適するケース

クラス変数は、次のような場合に向いています。

  • そのクラスに属するすべてのインスタンスで値を共有したい場合
  • インスタンスが何個生成されたかを数えるカウンタ
  • アプリケーション全体で共通の設定値(定数に近いもの)
  • デフォルト設定やフラグのような、クラス単位で共通の情報

具体例を見てみます。

Python
class AppConfig:
    # すべてのインスタンスで共有する設定値
    default_timeout = 30  # 秒
    debug_mode = False    # デバッグフラグ


class ApiClient:
    # 生成されたクライアントの数をカウント
    client_count = 0

    def __init__(self, name):
        self.name = name
        ApiClient.client_count += 1


c1 = ApiClient("client1")
c2 = ApiClient("client2")

print(ApiClient.client_count)  # 2
print(AppConfig.default_timeout)  # 30
実行結果
2
30

このように、「そのクラス全体で1つだけ持っていればよい情報かどうか」が、クラス変数を使うかどうかの判断ポイントになります。

クラス変数を使う際の注意点

クラス変数を使う際に特に気をつけたいポイントを整理します。

まず、ミュータブル(変更可能)なオブジェクトをクラス変数にすると、すべてのインスタンスで中身が共有されることです。

Python
class Bag:
    # クラス変数としてリストを定義 (危険なパターン)
    items = []

    def add_item(self, item):
        Bag.items.append(item)


bag1 = Bag()
bag2 = Bag()

bag1.add_item("apple")
bag2.add_item("banana")

print(bag1.items)  # ['apple', 'banana']
print(bag2.items)  # ['apple', 'banana']
print(Bag.items)   # ['apple', 'banana']
実行結果
['apple', 'banana']
['apple', 'banana']
['apple', 'banana']

意図としては「Bagごとに別々のitemsリストを持たせたい」のに、クラス変数にしてしまうと全インスタンスで共有されてしまいます。

このような場合は、インスタンス変数として__init__でリストを作るのが正しい書き方です。

Python
class SafeBag:
    def __init__(self):
        # インスタンス変数としてリストを持つ
        self.items = []

    def add_item(self, item):
        self.items.append(item)


bag1 = SafeBag()
bag2 = SafeBag()

bag1.add_item("apple")
bag2.add_item("banana")

print(bag1.items)  # ['apple']
print(bag2.items)  # ['banana']
実行結果
['apple']
['banana']

クラス変数でミュータブルな値(リスト、辞書、集合など)を扱う場合は、「本当に全インスタンスで1つを共有したいのか」を必ず確認するようにしてください。

インスタンス変数の特徴と使い方

インスタンス変数の初期化と__init__の役割

インスタンス変数は、通常__init__メソッドの中で初期化します。

__init__はコンストラクタとして、生成されたインスタンスの初期状態を設定する役割を持っています。

Python
class User:
    def __init__(self, name, age):
        # ここでインスタンス変数を定義・初期化
        self.name = name
        self.age = age


u1 = User("Alice", 20)
u2 = User("Bob", 30)

print(u1.name, u1.age)  # Alice 20
print(u2.name, u2.age)  # Bob 30
実行結果
Alice 20
Bob 30

このように、インスタンスごとに異なる情報を持たせたいときは、__init__の中でself.変数名としてインスタンス変数を定義するのが基本です。

インスタンス変数が適するケース

インスタンス変数は、次のような場合に向いています。

  • ユーザーごとの名前・年齢・メールアドレスなどの個別情報
  • 商品ごとの価格・在庫・説明文などの属性
  • 接続先ごとに異なる設定(ホスト名、ポート番号、認証情報など)
  • ゲームのキャラクターごとのHP、MP、位置情報など

つまり、「インスタンスごとに別々の状態を持つ必要があるもの」にはインスタンス変数を使うのが原則です。

Python
class Product:
    def __init__(self, name, price):
        self.name = name    # インスタンスごとに名前が違う
        self.price = price  # インスタンスごとに価格が違う


p1 = Product("Keyboard", 3000)
p2 = Product("Mouse", 1500)

print(p1.name, p1.price)  # Keyboard 3000
print(p2.name, p2.price)  # Mouse 1500
実行結果
Keyboard 3000
Mouse 1500

インスタンス変数とカプセル化

オブジェクト指向では、カプセル化(データを隠して安全に扱うこと)が重要です。

Pythonでは完全なアクセス制御はありませんが、_name__nameといった慣習を使ってインスタンス変数を守ります。

Python
class BankAccount:
    def __init__(self, owner, balance=0):
        self.owner = owner
        # 先頭にアンダースコアを付けて「内部用」であることを示す
        self._balance = balance

    def deposit(self, amount):
        if amount <= 0:
            raise ValueError("入金額は正の値である必要があります")
        self._balance += amount

    def withdraw(self, amount):
        if amount > self._balance:
            raise ValueError("残高不足です")
        self._balance -= amount

    def get_balance(self):
        return self._balance


account = BankAccount("Alice", 1000)
account.deposit(500)
print(account.get_balance())  # 1500
実行結果
1500

このように、インスタンス変数はできる限りメソッドを通して操作し、直接書き換えられないようにすることで、オブジェクトの整合性を保つことができます。

クラス変数とインスタンス変数の違いと使い分け

クラス変数 vs インスタンス変数の挙動比較

ここで、クラス変数とインスタンス変数の違いを表にまとめます。

項目クラス変数インスタンス変数
所属先クラス各インスタンス
個数クラスにつき1つインスタンスごとに1つずつ
共有の有無すべてのインスタンスで共有原則として共有しない(インスタンスごとに独立)
定義場所クラス定義直下(メソッドの外)メソッド内でself.変数として定義
主な用途共通設定、カウンタ、定数的な値個々のオブジェクトの状態・属性
更新の影響範囲クラス全体(すべてのインスタンス)そのインスタンスだけ

簡単な比較コードも見ておきます。

Python
class Sample:
    # クラス変数
    shared = 0

    def __init__(self, value):
        # インスタンス変数
        self.value = value


a = Sample(10)
b = Sample(20)

print("クラス変数 shared:", a.shared, b.shared, Sample.shared)  # 0 0 0
print("インスタンス変数 value:", a.value, b.value)            # 10 20

# クラス変数をクラスから更新
Sample.shared = 100
print("クラス変数 shared 更新後:", a.shared, b.shared, Sample.shared)  # 100 100 100

# インスタンス変数をインスタンスごとに更新
a.value = 999
print("インスタンス変数 value 更新後:", a.value, b.value)  # 999 20
実行結果
クラス変数 shared: 0 0 0
インスタンス変数 value: 10 20
クラス変数 shared 更新後: 100 100 100
インスタンス変数 value 更新後: 999 20

このように、クラス変数は「1つをみんなで使う」、インスタンス変数は「1人1つずつ持つ」というイメージで区別すると分かりやすくなります。

よくある誤解とバグ例

クラス変数とインスタンス変数の違いを曖昧にしたまま実装すると、次のようなバグを生みがちです。

誤解1: 「クラス変数をインスタンスごとに上書きできる」

Python
class Config:
    timeout = 30  # クラス変数

c1 = Config()
c2 = Config()

# 「c1だけtimeoutを変えたい」と思ってこう書く
c1.timeout = 10

print(c1.timeout)  # 10
print(c2.timeout)  # 30
print(Config.timeout)  # 30
実行結果
10
30
30

一見うまくいっているようですが、これはクラス変数を書き換えたのではなく、c1インスタンスに同名のインスタンス変数を追加しているだけです。

クラスから参照すると依然として30のままなので、場所によって参照している値が異なるという混乱を招きます。

「インスタンスごとの設定」にしたいのであれば、はじめからインスタンス変数として設計し、__init__の中で初期値を設定するのが適切です。

誤解2: ミュータブルなクラス変数の共有

先ほど触れたように、リストや辞書をクラス変数にして、インスタンスごとに別々に使えると誤解するパターンは非常に多いです。

Python
class User:
    # ユーザーごとに持たせたい「タグ」をクラス変数にしてしまった例
    tags = []

    def add_tag(self, tag):
        User.tags.append(tag)


u1 = User()
u2 = User()

u1.add_tag("admin")
u2.add_tag("premium")

print(u1.tags)  # ['admin', 'premium']
print(u2.tags)  # ['admin', 'premium']
実行結果
['admin', 'premium']
['admin', 'premium']

本来はユーザーごとに別々のタグリストを持たせたいなら、インスタンス変数にするべきです。

Python
class User:
    def __init__(self):
        self.tags = []  # インスタンスごとに独立

    def add_tag(self, tag):
        self.tags.append(tag)


u1 = User()
u2 = User()

u1.add_tag("admin")
u2.add_tag("premium")

print(u1.tags)  # ['admin']
print(u2.tags)  # ['premium']
実行結果
['admin']
['premium']

このようなバグを防ぐには、「このデータは全員で共有してよいのか、それとも1人ずつ別々に持つべきか」を常に意識することが大切です。

クラス変数とインスタンス変数の使い分けの判断基準

最後に、クラス変数とインスタンス変数をどのように使い分ければよいかを、判断基準としてまとめます。

1つ目の質問は、「この情報はインスタンスごとに異なるか?」です。

異なるのであれば、それはインスタンス変数にすべき情報です。

例えばユーザー名、年齢、パスワード、商品の価格などが該当します。

異ならない(どのインスタンスでも原則同じ)なら、2つ目の質問に進みます。

2つ目の質問は、「全インスタンスで共有しても問題ないか?」です。

アプリ全体の設定値や、生成されたインスタンスの数、共通の定数などであれば、クラス変数で管理したほうがシンプルです。

一方で、「将来的にインスタンスごとに変えたくなるかもしれない」「インスタンスごとの上書きが前提になりそう」といった場合は、安易にクラス変数にせず、インスタンス変数として設計したほうが安全です。

まとめると、目安は次のようになります。

  • インスタンス変数を選ぶとよいケース
    インスタンスの状態・属性を表すもの(ユーザー、商品、アカウントなどの固有情報)
  • クラス変数を選ぶとよいケース
    クラス全体で共有すべき設定やカウンタ、変更されにくい定数的な値

この基準を意識して設計することで、分かりやすくバグの起こりにくいクラス設計ができるようになります。

まとめ

クラス変数とインスタンス変数は、どちらもクラスの中で使われる変数ですが、「どこに属しているか」「どこまで共有されるか」が大きく異なります。

インスタンスごとに異なる状態を表すものはインスタンス変数にし、クラス全体で1つだけ持てばよい情報はクラス変数にする、という原則を押さえておけば、設計で迷う場面はぐっと減ります。

特にミュータブルなクラス変数の共有や、インスタンスからの誤った上書きはバグの温床になりやすいため、本記事の図解とコード例を参考に、日々のPython開発で意識的に使い分けてみてください。

クラスとオブジェクト指向

クラウドSSLサイトシールは安心の証です。

URLをコピーしました!