事前知識:インスタンス変数とクラス変数について
インスタンス変数
それぞれのインスタンスごとに独立した変数
宣言する方法
self.変数名 = 値
一般的にコンストラクタの内部で宣言される。
アクセス方法
self.変数名
例
class MyClass:
def __init__(self, name): # コンストラクタ:インスタンス作成時に自動的に呼ばれる
self.name = name # インスタンス変数 name を宣言する
def getName(self): # インスタンス変数 name の値を返す関数
return self.name # インスタンス変数 name にアクセスし、値を返す
if __name__ == "__main__":
a = MyClass("Sato") # インスタンス a を作成
b = MyClass("Tanaka") # インスタンス b を作成
print(a.getName()) # Sato
print(b.getName()) # Tanaka
クラス変数
全てのインスタンス間で共通した値を持つ変数
宣言する方法
class MyClass:
クラス変数 = 値
アクセス方法
**クラス名.**変数名
例
class MyClass:
number = 5
def __init__(self): # コンストラクタ:インスタンス作成時に自動的に呼ばれる
MyClass.number += 1 # クラス変数 number の値に1を足す
def getNumber(self): # クラス変数 number の値を返す関数
return MyClass.number # クラス変数 number にアクセスし値を返す
if __name__ == "__main__":
a = MyClass() # インスタンス a を作成
print(a.getNumber()) # 6
b = MyClass() # インスタンス b を作成
print(b.getNumber()) # 7
selfでクラス変数にアクセスしようとするとどうなるのか?
「self.変数名」としたときの挙動は以下のようになる。
- 同名のインスタンス変数が存在する場合
- インスタンス変数を参照する
- 同名のインスタンス変数が存在しないが、クラス変数は存在する場合
- クラス変数を参照し、同名のインスタンス変数を新たに生成する
- 同名のインスタンス変数もクラス変数も存在しない場合
- エラーを返す
ここで、クラス変数の型によって、selfでアクセスした際に値が変更できるか否かが変わる。
クラス変数がイミュータブルなオブジェクト(数値や文字列)な場合
- 同名のインスタンス変数が新たに生成される際に、値渡しでコピーが生成されるため、値が変更できない。※
クラス変数がミュータブルなオブジェクト(リストや辞書)な場合
- 同名のインスタンス変数が新たに生成される際に、参照渡しでコピーが生成されるため、値が変更できる。※
※追記:厳密には、Pythonには情報処理用語でいうところの「参照渡し」の操作は存在せず、値渡しのみ。ただし、ミュータブルなオブジェクトの演算の際はオブジェクトのメソッドが呼び出されるため、オブジェクト自身の値が変更可能。詳細はコメント欄参照。
これらの挙動は = で代入するときと同様。
参考:https://qiita.com/hrs1985/items/4e7bba39a35056de4e73
例
class MyClass:
number = 5
number_list = [5]
def __init__(self): # コンストラクタ:インスタンス作成時に自動的に呼ばれる
self.number += 1 # クラス変数 number の値で初期化されたインスタンス変数numberが生成され、インスタンス変数numberに1を足す
self.number_list[0] += 1 # クラス変数 number_list のリストで初期化されたインスタンス変数number_listが生成され、インスタンス変数number_listの0番目の要素に1を足す
def getNumber(self): # インスタンス変数 number の値を返す関数
return self.number # インスタンス変数 number にアクセスし値を返す
def getNumberList(self): # インスタンス変数 number_list の値を返す関数
return self.number_list[0] # インスタンス変数 number_list にアクセスし値を返す
if __name__ == "__main__":
a = MyClass() # インスタンス a を作成
print(a.getNumber()) # 6
print(a.getNumberList()) # 6
b = MyClass() # インスタンス b を作成
print(b.getNumber()) # 6
print(b.getNumberList()) # 7