クラス
クラスの定義
class Clsname:
pass
クラスは、データを属性として変数を保持し、振舞いをメソッドとして関数を定義します。数値や文字列などの各データ型はそれぞれのクラスで定義されています。
class文に続き任意のクラス名の、独自のクラスを定義します。クラス名は変数名と同じ命名規則で任意につけることができます。定義の内容はブロックとしてインデントします。
class クラス名:
メソッドや属性の定義
...
インスタンスの生成
class Clsname:
pass
c = Clsname()
print(c)
<__main__.Clsname object at 0x7f5273c12bf0>
クラス名を関数のように呼び出すと、クラスのインスタンス(実体)が生成され返ります。
クラス名()
変数 = クラス名()
属性の作成
class Cls:
pass
a = Cls()
a.x = 100
a.y = 200
print(a.x, a.y) # 100 200
インスタンスに「.(ドット)」で区切り任意の変数名を記述すると、その変数名がインスタンスの属性として追加されます。その属性にデータを代入することで、そのインスタンスにデータが格納されます。
このように、クラスから生成するインスタンスごとに、動的に属性を加えることができます。
インスタンス.属性 = 値
メソッドの定義と呼び出し
class Msg:
def show(self, msg):
print("message:" + msg)
m = Msg()
m.show("Hello") # message:Hello
クラス定義に関数を定義すると、その関数はクラスのメソッドになります。
メソッドとして定義する関数は、必ず先頭に1つの引数を定義します。先頭の引数は「現在のインスタンス」を参照します(慣習としてselfという名前が使われています)。引数のない関数でも最低1の引数を持つことになります。
def 関数名(self):
def 関数名(self, 引数, 引数,...):
クラスに定義されてたメソッドは、そのクラスのすべてのインスタンスから呼び出すことができます。インスタンスに「.(ドット)」で区切って関数のように呼び出します。
メソッドの呼び出しでは、クラスに定義した先頭の引数は渡しません。呼び出し時に、内部的にインスタンスの参照が先頭の引数に渡ります。
インスタンス.メソッド(引数, 引数, ...)
メソッドから属性を参照
class Cls:
def setattr(self, n, m):
self.x = n # selfはcを指す
self.y = m
c = Cls()
c.setattr(100, "ABC") # cがselfに渡る
print(c.x, c.y) # 100 ABC
インスタンスの属性をメソッドの中で生成できます。
インスタンスを参照する先頭の引数(self)に「.変数名」のように続けると、インスタンスの属性の参照になります。変数名が新規ならば属性の追加になります。
def method(self, ...):
self.属性名 = 値
メソッドからメソッドを呼び出し
class Cls:
def set(self, a):
self.s = a
def get(self):
return self.s
def show(self):
print("attr:", self.get())
c = Cls()
c.set("ABC")
c.show() # attr: ABC
メソッドの中から他のメソッドを呼び出すことができます。
インスタンスを参照する先頭の引数(self)に「.メソッド()」として、インスタンスのメソッドを呼び出します。
def method(self, ...):
self.othermethod(...)
コンストラクタ
class Cls:
def __init__(self, a):
self.x = a
print("new Cls:", a)
def show(self):
print("attr:", self.x)
c = Cls("ABC")
c.show()
new Cls: ABC
attr: ABC
__init__()というメソッドで、クラスのコンストラクタを定義します。
コンストラクタの__init__()メソッドは、インスタンスの生成時に自動的に呼び出されます。インスタンス生成時の引数が__init__()に渡されます。通常のメソッドと同様、定義の先頭の引数はインスタンスを参照しています。
コンストラクタにより、クラスのインスタンスの初期の属性の生成や、初期化処理を行うことができます。
def __init__(self, 引数, 引数,...):
__init__()を明示的に定義しない場合は、何もしないコンストラクタが暗黙に呼び出されます。
複数クラスのインスタンスを作成
class Cls:
def showx(self):
print("attr:", self.x)
c1 = Cls()
c1.x = 100
c2 = Cls()
c2.x = 200
c1.showx() # attr: 100
c2.showx() # attr: 200
c2.y = "ABC"
print(c2.y) # ABC
print(c1.y) # AttributeError
クラスから生成するインスタンスは、それぞれの実体として独立したオブジェクトです。インスタンスの変数に属性を追加した場合は、そのインスタンスのみへの追加になります。一方で、クラスに定義したメソッドは、どのインスタンスでも呼び出すことができます。
コンストラクタでインスタンスを初期化
class Cls:
def __init__(self, a):
self.x = a
def show(self):
print("attr:", self.x)
c1 = Cls("ABC")
c2 = Cls("DEF")
c1.show() # attr: ABC
c2.show() # attr: DEF
インスタンス生成時に、コンストラクタ__init__()に定義した処理が実行されます。コンストラクタに引数を与えることで、インスタンスごとの初期化ができます。
継承
クラスの継承による拡張
class CSuper:
def setx(self, a):
self.x = a
class CSub(CSuper):
def setxy(self, a, b):
self.setx(a) # CSuperのsetx()
self.y = b
def show(self):
print(self.x, self.y) # CSuperの属性xを参照
c = CSub()
c.setxy(100, 200)
c.show() # 100 200
クラスが、既存のクラスの定義を引継ぎ(継承)、新たに属性やメソッドを加えて拡張することができます。
継承される元になるクラスをスーパークラスと呼び、それを継承して拡張するクラスをスーパークラスに対するサブクラスと呼びます。
クラス定義のクラス名に続き「(スーパークラス名)」のように指定し、任意のクラスを継承します。
class サブクラス名(スーパークラス名):
サブクラスは、スーパークラスの定義を自身の中で定義したように取り込みます。
インスタンスからスーパークラスのメソッド呼び出し
class CSuper:
def setx(self, a):
self.x = a
class CSub(CSuper):
def sety(self, a):
self.y = a
def show(self):
print(self.x, self.y)
c = CSub()
c.setx(100) # CSuperのメソッドを呼び出す
c.sety(200)
c.show() # 100 200
c.x = 150
c.show() # 150 200
サブクラスとして生成したインスタンスから、スーパークラスの属性の参照や、スーパークラスのメソッドの呼び出しができます。
コンストラクタの継承
class CSuper:
def __init__(self, a):
self.x = a
class CSub(CSuper):
def sety(self, a):
self.y = a
def show(self):
print(self.x, self.y)
c = CSub(100) # CSuperの__init__()
c.sety(200)
c.show() # 100 200
サブクラスはスーパークラスのコンストラクタ__init__()を継承します。
サブクラスのインスタンス生成時に、サブクラスのコンストラクタが定義されておらず、スーパークラスに定義があればそれが呼び出されます。
メソッドのオーバーライド
class CSuper:
def set(self, a):
self.x = a
class CSub(CSuper):
def set(self, a, b): # オーバーライド
self.x = a
self.y = b
def show(self):
print(self.x, self.y)
c = CSub()
c.set(100, 200) # CSubのset()
c.show() # 100 200
c.set(300) # TypeError CSuper側は呼び出されない
スーパークラスと同じメソッドをサブクラスで定義した場合、サブクラスのインスタンスからそのメソッドを呼び出すと、サブクラス側が呼び出されます。
サブクラスがスーパークラスのメソッドを上書きしたようになります(オーバーライド)。
スーパークラス側のメソッドを明示的に呼び出す
class CSuper:
def set(self, a):
self.x = a
class CSub(CSuper):
def set(self, a, b): # オーバーライド
super().set(a) # CSuperのset()を呼び出す
self.y = b
def show(self):
print(self.x, self.y)
c = CSub()
c.set(100, 200) # CSubのset()
c.show() # 100 200
サブクラスの中で、super()により明示的にスーパークラス側のメソッドを呼び出すことができます。
super().メソッド(引数, 引数,...)
クラス名でスーパークラスのメソッドを明示的に呼び出す
class CSuper:
def set(self, a):
self.x = a
class CSub(CSuper):
def set(self, a, b): # オーバーライド
CSuper.set(self, a) # CSuperのset()を呼び出す
self.y = b
def show(self):
print(self.x, self.y)
c = CSub()
c.set(100, 200) # CSubのset()
c.show() # 100 200
クラス名に「.(ドット)」を続けてメソッドを呼び出すことで、呼び出すメソッドのクラスを直接指定できます。この場合は、先頭の引数に現在のインスタンス(self)を渡す必要があります。この方法でスーパークラスを指定してメソッドを呼び出すことができます。
スーパークラス名.メソッド(self, 引数, 引数,...)
コンストラクタのオーバーライド
class CSuper:
def __init__(self, a):
self.x = a
class CSub(CSuper):
def __init__(self, a, b): # オーバーライド
super().__init__(a) # CSuperの__init__()を呼び出す
self.y = b
def show(self):
print(self.x, self.y)
c = CSub(100, 200)
c.show() # 100 200
サブクラスはスーパークラスのコンストラクタをオーバーライドできます。サブクラスのインスタンスの生成時にはサブクラスに__init__()メソッドの定義があれば、それを実行します。
オーバーライドしたコンストラクタからスーパークラスの初期化を実行するために、super()により明示的にスーパークラス側のコンストラクタを呼び出すことができます。
super().__init__(引数, 引数,...)
多重継承
class CSuperA:
def set(self, a):
self.x = a
class CSuperB:
def set(self, a):
self.y = a
class CSub(CSuperA, CSuperB):
def set(self, a, b, c):
CSuperA.set(self, a) # CSuperAのset()を呼び出す
CSuperB.set(self, b) # CSuperBのset()を呼び出す
self.z = c
def show(self):
print(self.x, self.y, self.z)
c = CSub()
c.set(100, 200, 300) # CSubのset()
c.show() # 100 200 300
複数のスーパークラスを同時に継承することができます(多重継承)。
サブクラスの定義に、カンマで区切って複数のスーパークラスを指定します。
class サブクラス名(スーパークラス名, スーパークラス名,...):
多重継承の場合は、サブクラスのメソッドからスーパークラスのメソッドを呼び出すとき、super()ではスーパークラスが特定できないので、クラス名を明示する方法で呼び出す必要があります。
クラス属性/メソッド
クラス属性
class Cls:
sum = 0
def __init__(self, a):
self.x = a
Cls.sum += a
print(Cls.sum) # 0 定義時から存在する
c1 = Cls(3)
print(c1.x, c1.sum) # 3 3 c1.sumはCls.sumと同じ
c2 = Cls(5)
print(c2.x, c2.sum) # 5 8 c2.sumはCls.sumと同じ
クラス定義に、変数の代入式を記述すると、その変数はクラス属性としてクラス定義時から存在する属性になります。クラス属性は、どのインスタンスにも属さないクラスで唯一の属性になります。
class クラス:
変数 = 初期値
クラス属性は、どのインスタンスからも唯一の属性を参照します。インスタンス属性とクラス属性が同名の場合は、インスタンスはインスタンス属性を参照します。「クラス名.属性」は必ずクラス属性の参照になります。
クラス名.属性
動的に生成するクラス属性
class Cls:
def __init__(self, a):
self.x = a
Cls.sum += a
Cls.sum = 0
print(Cls.sum) # 0 Clsにsumが生成
c1 = Cls(3)
print(c1.x, Cls.sum) # 3 3
c2 = Cls(5)
print(c2.x, Cls.sum) # 5 8
クラス定義以降で「クラス名.属性」に初期値を代入すると、そのクラスのクラス属性として動的に生成されます。
クラスメソッド
class Cls:
sum = 0
@classmethod
def addsum(cls, a):
cls.sum += a
@classmethod
def getsum(cls):
return cls.sum
def __init__(self, a):
self.x = a
Cls.addsum(a)
c1 = Cls(3)
print(c1.x, c1.getsum()) # 3 3
c2 = Cls(5)
print(c2.x, c2.getsum()) # 5 8
クラス定義で、@classmethodデコレータに続いて定義するメソッドはクラスメソッドとして定義されます。クラスメソッドは、クラスの名前空間に唯一定義される、どのインスタンスにも属さないメソッドになります。そのため、クラスメソッドの処理ではインスタンス属性やインスタンスのメソッドは参照・呼び出しができません。
クラスメソッドは、必ず先頭に1つの引数を定義します。先頭の引数は「クラス」への参照です(慣習としてclsという名前が使われています)。
@classmethod
def クラスメソッド(cls, 引数, 引数,...):
クラスメソッドは、どのインスタンスからも唯一のメソッドを呼び出します。「クラス名.クラスメソッド()」はあらゆる場所から唯一のクラスメソッドを呼び出します。
クラス名.クラスメソッド(引数, 引数,...)
アクセス制御
ゲッター・セッターメソッド
class Cls:
def getx(self):
return "---" + self._attrx # _attrxが内部属性
def setx(self, x):
self._attrx = x + "---"
attrx = property(getx, setx)
c1 = Cls()
c1.attrx = "ABC"
print(c1.attrx) # ---ABC---
c2 = Cls()
c2.attrx = "DEF"
print(c2.attrx) # ---DEF---
インスタンスの属性への設定や参照を、get()やset()のようなメソッドを用意して直接参照させないようにする方法がありますが、属性への代入と参照時に自動的にそのようなゲッター・セッターメソッドを呼び出してアクセスさせることができます。
属性に対するゲッター・セッターメソッドをそれぞれ定義し、それらをproperty()関数に指定して呼び出し、戻り値を「仮の属性名」に代入します。
仮の属性名 = property(ゲッターメソッド, セッターメソッド)
インスタンスは仮の属性名で通常の属性のように参照や代入操作を行います。そのとき、自動的に参照操作はゲッターメソッド、代入操作はセッターメソッドが呼び出されます。
ゲッターメソッドとセッターメソッドの中では、仮ではない実際のインスタンス属性への操作などを実装します。
インスタンス.仮の属性名 (ゲッターメソッドの呼び出し)
インスタンス.仮の属性名 = 値 (セッターメソッドの呼び出し)
このように、インスタンスから属性を直接操作することからアクセスを保護することができます。
デコレータによるゲッター・セッターメソッド
class Cls:
@property
def attrx(self):
return "---" + self._attrx
@attrx.setter
def attrx(self, x):
self._attrx = x + "---"
c1 = Cls()
c1.attrx = "ABC"
print(c1.attrx) # ---ABC---
c2 = Cls()
c2.attrx = "DEF"
print(c2.attrx) # ---DEF---
もう一つの方法として、ゲッターメソッドとセッターメソッドを、デコレータでメソッドを修飾することで定義できます。
ゲッターメソッドとして定義するメソッドを@propertyデコレータで修飾し、セッターメソッドとして定義するメソッドを@仮の属性名.setterデコレータで修飾します。そして、それらのメソッドはどちらも「仮の属性名()」の同じメソッド名で定義します。
@property
def 仮の属性名(self):
return 属性
@仮の属性名.setter
def 仮の属性名(self, 引数, 引数,...):
命名法によるアクセス制限
class Cls:
def get(self):
return "---" + self._attrx
def set(self, x):
self._attrx = x + "---"
c = Cls()
c.set("ABC")
print(c.get()) # ---ABC---
Pythonの慣習として、アンダーバー(アンダースコア)からはじまる属性は、プライベートであるとしてインスタンスから直接参照しないルールがあります。ただし、これはルールを無視すれば参照可能です。
難読化(マングリング)によるアクセス制限
class Cls:
def get(self):
return "---" + self.__attrx
def set(self, x):
self.__attrx = x + "---"
c = Cls()
c.set("ABC")
print(c.get()) # ---ABC
c._Cls__attrx = "---ABC---"
print(c._Cls__attrx) # ---ABC
「__」から始まる属性名は、インタプリタが内部的に別の名前に変換(難読化)するため、定義上のスペルではアクセスできなくなります。ただし次のような変換法則なので、強い難読化ではありません。
__属性名 ⇒ _クラス名__属性名
特殊メソッド
演算子のオーバーロード
class Cls:
def __init__(self, a):
self.x = a
def __add__(self, c):
return self.x + "-!-" + c.x
c1 = Cls("ABC")
c2 = Cls("DEF")
print(c1 + c2) # ABC-!-DEF
c1.__add__(c2)
print(c1 + c2) # ABC-!-DEF
クラスのインスタンスに対して演算子で演算が行われようとしたときに、そのクラスの特性に対応した演算処理を実装する特殊メソッドがあります。例えば文字列の「+」による加算は、文字列クラスとしての加算メソッドの実装により文字列の連結が行われます。
演算子による演算時に呼び出されるそれらの特殊メソッドを実装(オーバーロード)することで、定義したクラスのインスタンスの変数を使った演算ができるようになります。
演算子の特殊メソッドは「__演算__」のような名前になっています。特殊メソッドの第一引数は自身のインスタンス(self)で、二項演算ならば右項のインスタンスを第二引数で受けます。例えば加算演算のオーバーロードは、__add__()という特殊メソッドを実装します。
def __add__(self, インスタンス右項):
インスタンス左項.__add__(self, インスタンス右項)
文字列化のオーバーロード
class Cls:
def __init__(self, a):
self.x = a
def __str__(self):
return "<<" + str(self.x) + ">>"
c = Cls(123)
print(str(c)) # <<123>>
str()関数はクラスのインスタンスをそれぞれの形式で何らかの文字列に変換します。このとき、クラスのインスタンスに対し特殊メソッドの__str__()が呼び出されます。
__str__()メソッドを定義して実装することで、インスタンスがstr()関数に渡されたときに適当な文字列を返すことができます。__str__()メソッドは自身のインスタンス(self)のみ引数に取ります。
def __str__(self):
文字例 = インスタンス.__str__(self)
その他の特殊メソッド
操作
|
特殊メソッド
|
使い方
|
加算
|
__add__(self, other)
|
self + other
|
減算
|
__sub__(self, other)
|
self - other
|
乗算
|
__mul__(self, other)
|
self * other
|
除算
|
__truediv__(self, other)
|
self / other
|
切り捨て除算
|
__floordiv__(self, other)
|
self // other
|
剰余
|
__mod__(self, other)
|
self % other
|
べき乗
|
__pow__(self, other)
|
self ** other
|
イコール
|
__eq__(self, other)
|
self == other
|
ノットイコール
|
__ne__(self, other)
|
self != other
|
小なり
|
__lt__(self, other)
|
self < other
|
大なり
|
__gt__(self, other)
|
self > other
|
小なりイコール
|
__le__(self, other)
|
self <= other
|
大なりイコール
|
__ge__(self, other)
|
self >= other
|
文字列に変換
|
__str__(self)
|
str(self)
|
長さ
|
__len__(self)
|
len(self)
|