✍️

Pythonのクラス変数とインスタンス変数

2025/02/14に公開

はじめに

Pythonのクラス変数とインスタンス変数の値の持ち方がよくわからなかったので整理する。

登場する用語達
  • Human ➡ Humanクラス
  • human_name ➡ 変数
  • change_name ➡ 名前を書き換えるメソッド
  • first_human ➡ インスタンス
  • second_human ➡ インスタンス
  • init() ➡ 特殊メソッド

Pythonのクラス変数

Pythonのクラス変数は、クラスで保持する変数のため、すべてのインスタンスで共有される。
例えば、下記のコードを例に詳しく見てみる。

class Human:
    human_name:str = "Takeshi"

    def change_name(self, human_name):
        Human.human_name = human_name

first_human = Human()
second_human = Human()

print(first_human.human_name)
print(second_human.human_name)

first_human.change_name("Jiro")

# 区切り線
print("-------------")

print(first_human.human_name)
print(second_human.human_name)

解説

上から区切って解説していく。
まず、Humanクラスを作成し、クラス変数としてhuman_name="Takeshi"を定義

class Human:
    # クラス変数
    human_name:str = "Takeshi"
    # メソッド
    def change_name(self, human_name):
        Human.human_name = human_name

そして、Humanクラスでインスタンス化

first_human = Human()
second_human = Human()

printでfirst_humanとsecond_humanのhuman_name変数を出力

print(first_human.human_name)
print(second_human.human_name)

出力結果として、クラス変数で指定したTakeshiが出力。
first_humanとsecond_humanはHumanクラスのクラス変数を持つので、Takeshiを出力している。

Takeshi
Takeshi

ここで、first_humanを"Jiro"に変更するchange_nameメソッドを実行する。

first_human.change_name("Jiro")
change_nameメソッドについて

change_nameメソッドは、Humanクラスのクラス変数であるhuman_nameに、引数で受け取った値を格納することでクラス変数であるhuman_nameの値"Takeshi"を変更しようとしている。

def change_name(self, human_name):
    Human.human_name = human_name

もう一度、printでfirst_humanとsecond_humanのhuman_name変数を出力

print(first_human.human_name)
print(second_human.human_name)

出力結果は、Jiro Jiro となってしまった。
first_humanのhuman_nameを変更したかったのに、second_humanもJiroとなってしまった。

Jiro
Jiro

原因

原因は、first_humanとsecond_humanが共通のクラス変数、human_nameを参照していたから。

図1:初期状態
初期状態では、クラス変数の値"Takeshi"を持っているが、change_nameメソッドでクラス変数の値を"Jiro"に変更することで、参照しているすべてのインスタンスに影響を及ぼしてしまう。

図2:change_nameメソッド実行

Pythonのインスタンス変数

Pythonのインスタンス変数は、インスタンス単位で保持する固有の変数となっている。
例えば、下記のコードを例に詳しく見てみる。

class Human:
    def __init__(self, human_name="Takeshi"):
        self.human_name = human_name

    def change_name(self, human_name):
        self.human_name = human_name

first_human = Human()
second_human = Human()

print(first_human.human_name)
print(second_human.human_name)

first_human.change_name("Jiro")

# 区切り線
print("-------------")

print(first_human.human_name)
print(second_human.human_name)

解説

上から区切って解説していく。
まず、Humanクラスを作成し、特殊メソッド__init__()内にインスタンス変数を定義しデフォルト値に"Takeshi"を設定。

__init__()について

init()はインスタンスを初期化するPythonの特殊メソッドとなっている。インスタンス変数は、この特殊メソッド内で定義する。また、selfを使用して引数を与える。

class Human:
    # インスタンス変数
    def __init__(self, human_name:str="Takeshi"):
        self.human_name = human_name

    def change_name(self, human_name):
        self.human_name = human_name

Humanクラスでインスタンス化

first_human = Human()
second_human = Human()

printでfirst_humanとsecond_humanのhuman_name変数を出力

print(first_human.human_name)
print(second_human.human_name)

出力結果として、インスタンス変数で指定したデフォルト値のTakeshiが出力。

Takeshi
Takeshi

first_humanを"Jiro"に変更するchange_nameメソッドを実行する。

first_human.change_name("Jiro")

printでfirst_humanとsecond_humanのhuman_name変数を出力

print(first_human.human_name)
print(second_human.human_name)

出力結果は、Jiro Takeshi となった。

Jiro
Takeshi

理由

クラス変数が共通なのに対して、インスタンス変数はインスタンスごとに固有であるため、値の保持が可能になる。

図3:初期化

インスタンス化時に初期化されたインスタンス変数のデフォルト値"Takeshi"を受け取るが、change_nameメソッド実行によって書き換わるのは、first_humanのインスタンス変数のみとなり、Jiroに書き換わる。


図4:change_nameメソッド実行

まとめ

  • クラス変数は共通
  • インスタンス変数は固有

Discussion