[解決!Python]クラスを定義するには:解決!Python
インスタンス変数/インスタンスメソッド/クラスメソッド/スタティックメソッド/プロパティなどを含んだクラスの定義方法と注意点を紹介する。
データ属性(インスタンス変数)を持つクラス
class MyClass1:
def __init__(self, x, y):
self.x = x
self.y = y
mc = MyClass1(1, 2)
print(f'x: {mc.x}, y: {mc.y}') # x: 1, y: 2
説明は以下の「データ属性(インスタンス変数)を持つクラス」を参照のこと。
メソッド(インスタンスメソッド)を持つクラス
class MyClass2:
def __init__(self, x, y):
self.x = x
self.y = y
def show_attr(self):
print(f'x: {self.x}, y: {self.y}')
def set_x(self, value):
self.x = value
def set_y(self, value):
self.y = value
mc = MyClass2(1, 2)
mc.show_attr() # x: 1, y: 2
mc.set_x(10)
mc.set_y(20)
mc.show_attr() # x: 10, y: 20
説明は以下の「メソッド(インスタンスメソッド)を持つクラス」を参照のこと。
クラス変数を持つクラス
class MyClass3:
clsVar = 'class variable'
def __init__(self):
pass
def show_clsVar(self):
print(f'self.clsVar: {self.clsVar}')
print(f'MyClass3.clsVar: {MyClass3.clsVar}')
def change_clsVar(self, value):
self.clsVar = 'with self.clsVar: ' + value
MyClass3.clsVar = 'with MyClass3.clsVar: ' + value.upper()
mc = MyClass3()
mc.show_clsVar()
# 出力結果:
# self.clsVar: class variable
# MyClass3.clsVar: class variable
mc.change_clsVar('foo')
mc.show_clsVar()
# 出力結果:
# self.clsVar: with self.clsVar: foo
# MyClass3.clsVar: with MyClass3.clsVar: FOO
説明は以下の「クラス変数を持つクラス」を参照のこと。
クラスメソッドを持つクラス
class MyClass4:
clsVar = 'class variable'
def __init__(self):
pass
def show_clsVar1(self):
print(f'self.clsVar: {self.clsVar}')
@classmethod
def show_clsVar2(cls):
print(f'cls.clsVar: {cls.clsVar}')
@classmethod
def change_clsVar(cls, value):
print(f'brefore: {cls.clsVar}')
cls.clsVar = value
print(f'after: {cls.clsVar}')
mc = MyClass4()
mc.show_clsVar1() # self.clsVar: class variable
mc.show_clsVar2() # cls.clsVar: class variable
MyClass4.show_clsVar2() # cls.clsVar: class variable
mc.change_clsVar('changed')
MyClass4.show_clsVar2() # cls.clsVar: changed
説明は以下の「クラスメソッドを持つクラス」を参照のこと。
スタティックメソッド(静的メソッド)を持つクラス
class MyClass5:
PI = 3.14159
def __init__(self):
pass
@staticmethod
def double(x):
return x * 2
@staticmethod
def square(x):
return x ** 2
@staticmethod
def area_of_circle(r):
return MyClass5.PI * r ** 2
y = MyClass5.double(2)
print(y) # 4
y = MyClass5.square(4)
print(y) # 16
y = MyClass5.area_of_circle(1)
print(y) # 3.14159
mc = MyClass5()
y = mc.square(3)
print(y) # 9
説明は以下の「スタティックメソッド(静的メソッド)を持つクラス」を参照のこと。
プロパティを持つクラス(1)
class MyClass6:
def __init__(self, x):
self._x = x
def get_x(self):
return self._x
def set_x(self, value):
self._x = value
def del_x(self):
del self._x
x = property(get_x, set_x, del_x, 'property x')
mc = MyClass6(100)
print(mc.x) # 100
mc.x = 200
print(mc.x) # 200
del mc.x
print(mc.x) # AttributeError
mc.x = 10
print(mc.x) # 10
説明は以下の「プロパティを持つクラス(1)」を参照のこと。
プロパティを持つクラス(2)
class MyClass7:
def __init__(self, x):
self._x = x
@property
def x(self):
return self._x
@x.setter
def x(self, value):
self._x = value
@x.deleter
def x(self):
del self._x
mc = MyClass7(100)
print(mc.x) # 100
mc.x = 200
print(mc.x) # 200
del mc.x
print(mc.x) # AttributeError
mc.x = 10
print(mc.x) # 10
説明は以下の「プロパティを持つクラス(2)」を参照のこと。
データ属性(インスタンス変数)を持つクラス
Pythonのクラスはclass文で定義する。クラスにはさまざまな属性を持たせられるが、その中でも必ずといっていいほど使うことになるのがデータ属性(インスタンス変数)だ。
データ属性を含むクラスを定義する例を以下に示す。
class MyClass1:
def __init__(self, x, y):
self.x = x
self.y = y
これにより関数のようにして呼び出し可能なMyClass1オブジェクト(クラスオブジェクト)が作成される。そして、「MyClass1(1, 2)」のようにして、これを呼び出すことでMyClass1クラスのインスタンス(オブジェクト)が作成される。
「MyClass(1, 2)」のようにして呼び出した際に指定した引数は、__init__メソッドと呼ばれる、インスタンスの初期化を行うためのメソッドへと渡される。このメソッドの先頭パラメーター「self」はインスタンス自身であり、インスタンス生成時にプログラマーが明示的に指定する必要はない(メソッドが呼び出される際にPython処理系により自動的に設定される)。
__init__メソッドの内部では、初期化の対象となるインスタンス自身「self」と、そのパラメーターを使って、何らかの初期化処理を行う。上の例では、自身の属性「self.x」「self.y」に2つのパラメーターの値を渡すことで初期化を行っている(これは典型的な例)。
実際のインスタンス生成の例を以下に示す。
mc = MyClass1(1, 2)
print(f'x: {mc.x}, y: {mc.y}') # x: 1, y: 2
メソッド(インスタンスメソッド)を持つクラス
データ属性と共にクラスでよく使われるのが、インスタンスが持つ各種属性を使って何らかの処理を行うメソッド(インスタンスメソッド)だ。__init__メソッドがそうだったように、通常のメソッドでは自身を参照するselfが第1パラメーターとなり、その後にメソッド呼び出し時に使用する各種の値を受け取るパラメーターが並ぶ。__init__メソッドと同様、呼び出し側がselfを明示的に指定する必要はなく、「インスタンス.メソッド(self以外のパラメーターに渡す値)」として呼び出せば、呼び出しに使用したメソッドが自動的にselfに代入される。
以下にメソッド(インスタンスメソッド)を持つクラスの例を示す。
class MyClass2:
def __init__(self, x, y):
self.x = x
self.y = y
def show_attr(self):
print(f'x: {self.x}, y: {self.y}')
def set_x(self, value):
self.x = value
def set_y(self, value):
self.y = value
この例では、show_attrメソッドにはself以外にパラメーターがない。そのため、このメソッドは引数なしで呼び出しを行う。set_xメソッドとset_yメソッドは、__init__メソッドで初期化したx属性とy属性の値を書き換えるもので、呼び出し時には引数を1つ指定する。
実際の使用例を以下に示す。
mc = MyClass2(1, 2)
mc.show_attr() # x: 1, y: 2
mc.set_x(10)
mc.set_y(20)
mc.show_attr() # x: 10, y: 20
クラス変数を持つクラス
あるクラスのインスタンス全てで共有したい情報がある場合、それらはクラス変数に保存しておくのが一般的だ。class文の直下で(メソッド定義の外側で)変数を定義すると、それがクラス変数となる。
クラス変数には、インスタンスメソッド/クラスメソッド(後述)/スタティックメソッド(後述)からアクセスが可能だ。そのアクセスの仕方には大きく2種類がある。インスタンスメソッドでは「self.クラス変数名」あるいは「クラス名.クラス変数名」としてアクセスが可能だ。他の2つのメソッドからは「クラス名.クラス変数名」としてアクセスする。
値を参照するだけなら、2つの方法のどちらを使っても問題ないが、クラス変数に値を代入するのであれば、「クラス名.クラス変数名 = 値」とする必要がある点には注意すること。「self.クラス変数名 = 値」はクラス変数名と同じ名前の属性をデータ属性として自身に追加するだけだ。
以下に例を示す。
class MyClass3:
clsVar = 'class variable' # クラス変数
def __init__(self):
pass
def show_clsVar(self):
print(f'self.clsVar: {self.clsVar}') # selfを使ってアクセス
print(f'MyClass3.clsVar: {MyClass3.clsVar}') # クラス名を使ってアクセス
def change_clsVar(self, value):
self.clsVar = 'with self.clsVar: ' + value # self.clsVar属性を追加
MyClass3.clsVar = 'with MyClass3.clsVar: ' + value.upper()
この例のshow_clsVarメソッドでは、上で述べた「self.クラス変数名」「クラス名.クラス変数名」の両方の手段でクラス変数clsVarの値を読み出している。一方、change_clsVarメソッドでは同じく2つの方法でclsVarに代入をしている。
このクラスを実際に使う例を示す。
mc = MyClass3()
mc.show_clsVar()
# 出力結果:
# self.clsVar: class variable
# MyClass3.clsVar: class variable
読み出しではどちらも同じクラス変数にアクセスしているので、同じ値が表示されている。しかし、change_clsVarメソッドを呼び出すと次のようになる。
mc.change_clsVar('foo')
mc.show_clsVar()
# 出力結果:
# self.clsVar: with self.clsVar: foo
# MyClass3.clsVar: with MyClass3.clsVar: FOO
change_clsVarメソッドにある「self.clsVar = ……」と「MyClass3.clsVar = ……」はどちらもクラス変数clsVarの値を変更しようとしているが、前者ではself(このメソッドの呼び出しで使用したインスタンス)にデータ属性として「clsVar」を追加してしまう。そのため、その後のshow_clsVarメソッドを呼び出すと、別々の値が表示されるようになる。
クラスメソッドを持つクラス
Copyright© Digital Advantage Corp. All Rights Reserved.