理由はそのうち考える

まずやってみよう

Python学習メモ:クラス

gihyo.jp

クラス

クラス定義

Pythonのクラス定義は以下の通り。

class クラス名(基底クラス名):
    def メソッド名(引数, …):
        処理
        return 戻り値

クラスを継承したい場合はクラス名に()をつけて指定する。省略するとobjectクラスを継承する。

インスタンス生成

クラスオブジェクトに()をつけて呼び出すとインスタンスが作成できる。オブジェクトに渡された引数は、作成されたインスタンスのメソッド __init__()に渡され、インスタンスの初期化に利用される。

class MyClass:
    def __init__(self, num):
        self.num = num
    def printNum(self):
        print(num)

x = MyClass(10)
x.printNum()

インスタンス

インスタンスメソッド

インスタンスメソッドはクラス定義中に定義される関数。通常の関数定義と異なる点は、第一引数が必ずインスタンス自身のオブジェクトになること。仮引数名には慣例としてselfが使用される。

インスタンス変数

インスタンスの属性に値を代入すると、インスタンス変数を定義できる。インスタンス変数は、インスタンスごとに独立した値となる。インスタンス生成後に変数を定義して使用することができる点は、ちょっととっつきにくいかもしれない。クラス共通の変数にしたい場合は、__init__()を使用する。

__init__()

インスタンスの初期化を行う特殊メソッド。インスタンスの生成直後に自動で呼び出される。__init__()でインスタンスに属性を追加すると、 このクラスのすべてのインスタンスがその属性を持つことになる。

なんとなくコンストラクタをイメージしそうだが、__init__()はインスタンス生成後に呼び出される点で異なる。なおPythonにおけるコンストラクタにあたるメソッドは別にあり、__new__()である。クラスオブジェクトを呼び出しインスタンス化を行った時の処理の流れとしては、まず始めに__new__()が呼びだされ、その戻り値が__init__()の第一引数selfに渡される。

Pythonではインスタンスの初期化は殆ど__init__()で対応でき、__new__()を使用することは少ないそう。また__new__(()はインスタンスを戻り値とすることから、これを変更してしまうと使用者から想像できない問題を引き起こすことがあるため、__new__(()の使用はどうしようもない場合を除いて基本的に避ける。

プロパティ

@propertyでインスタンスメソッドを定義するとプロパティになる。 プロパティは()なしで呼び出せ、変数のように扱える。@プロパティ名.setter でセッターを定義する。

class MyClass:
    def __init__(self, num):
        self._num = num
    @property
    def Num(self):
        return self._num
    @Num.setter
    def Num(self, value)
        self._num = value

x = MyClass(100)
x.Num   # 100
x.Num = 200
x.Num   # 200

プライベート属性

Pythonにはプライベート属性がないが、属性の先頭にアンダースコア2つ(__)をつけると名前修飾が行われる。名前修飾はサブクラスでの名前衝突を防ぐために行われ、クラス名がアンダースコアの前につけられる。例えばMyClassにある__numはMyClass__numとなる。外部からアクセスする際は名前修飾後の変数である必要があり、そのままだとアクセスできない。

クラス変数とクラスメソッド、スタティックメソッド

クラス変数

クラスオブジェクトに紐づく変数。クラスインスタンスからも参照可能で、すべてのインスタンスで同じ変数が共有される。クラス変数を更新する場合はクラスオブジェクトを介して行う必要があり、インスタンスを介して代入すると、新たなインスタンス変数が作成されることになる。また同名のインスタンス変数が定義された場合はそちらが優先される。

クラスメソッド

クラスオブジェクトに紐づくメソッド。@classmethodを付けることで定義できる。第一引数にクラスオブジェクトが渡されること以外はインスタンスメソッドと同様に扱える。この場合、仮引数名にはselfではなくclsとすることが慣例とされる。

スタティックメソッド

@staticmethodとするとスタティックメソッドになる。スタティックメソッドの引数にはインスタンスやクラスが渡されることはない。つまりただの関数と同じで、クラスなしに関数のみを定義できるPythonでは使われることはあまりないらしい。

継承

メソッドのオーバーライド

基底クラスが持つメソッドと同名のメソッドを定義するとオーバーライドできる。オーバーライドしたメソッド内で基底クラスのメソッドを使用したい場合はsuper()を利用して明示的に呼び出す。

objectクラス

Pythonでは、組み込み型を含めた全てのクラスの基底クラスとしてobjectクラスがある。そのため組み込み型を継承してサブクラスを定義することもできる。