Pythonのクラスと継承【プログラミング初心者向け教材】

プログラミング

プログラミングをチームで効率よく開発するためには、担当領域を決めたり、似たようなコードが作らないようにするなどの工夫が必要となります。

プログラムを役割や機能に応じて分割することをモジュール分割と言ったりしますが、その際に必要となる概念がクラスです。

適切なクラス分割を行うことで、無駄がなくて読みやすく、メンテナンスのしやすいプログラムにすることができます。

プログラミング初心者にとっては、理解が難しい分野ではありますが、チームで開発するプログラマとなるためには必須の知識となります。

本記事では、Pythonのクラスと継承についてまとめます。

プログラミング初心者の方の学習や、忘れてしまった方の復習として、参考にしていただければ幸いです。

記載しているプログラムは、Python3.6.8を使って動作確認をしています。

Pythonのクラスと継承

Pythonのクラスと継承について、以下の内容を採り上げます。

  • クラスの定義方法
  • コンストラクタ
  • インスタンス化
  • インスタンスメソッド
  • インスタンス変数
  • クラスメソッド
  • 静的メソッド
  • クラス変数
  • クラスの継承

クラスの定義方法

クラスとは、動作(メソッド)や状態(プロパティ)を持つ構造(オブジェクト)です。

クラスを定義するには、class キーワードによって宣言します。
例えばPersonクラスを宣言するには、以下のように記述します。

class Person:

コンストラクタ

コンストラクタは、そのクラスからインスタンスを作成(後述)した際に、最初に実行されるメソッドです。
通常はクラスの初期化処理を記述ために用いられます。

コンストラクタを定義するには、__init__ メソッドを定義します。
__init__ メソッドの第一引数には必ず self が必要です。(self という名前でなければいけないわけではないですが、慣例となっています)

class Person:
    def __init__(self):
        self.age = 30

インスタンス化

定義したクラスを利用するためには、インスタンス化する必要があります。
インスタンス化とは実体を作ることで、クラス定義は実体を作るための雛形やテンプレートのようなもので、インスタンス化すると実物が作成されるというイメージです。

インスタンス化するにはクラス名で呼出します。
以下の例では、Personクラスをインスタンス化して、personという変数に代入しています。

person = Person()

インスタンスメソッド

クラスにおけるメソッドの役割は、そのクラスの動作(振る舞い)を定義するものになります。
例えば、Person(人間)クラスであれば、歩く、食べる、寝るという動作がクラスとしてのメソッドになります。

Pythonでは、第一引数にインスタンス(自分自身)を受け取るメソッドをインスタンスメソッドと呼びます。

class Person:
    def walk(self):
        print("歩きます")
    def eat(self):
        print("食べます")

上記のクラス定義をインスタンス化して実行すると、以下のようになります。
インスタンスメソッドの実行は、インスタンスを作成する必要があります。

person = Person()
person.walk() # -> 歩きます
person.eat() # -> 食べます

インスタンス変数

インスタンス化されたオブジェクト自身が保持する変数をインスタンス変数と呼びます。
インスタンス変数は、コンストラクタやアクセッサを通して設定することが多いです。

コンストラクタで設定

コンストラクタの引数で設定したい値を受取り、自身のインスタンス(self)の変数として設定します。

class Person:
    def __init__(self, height, weight):
        self.age = 30
        self.height = height
        self.weight = weight

person = Person(170, 60)
print(person.height) # -> 170
print(person.weight) # -> 60

アクセッサで設定

通常のインスタンス変数では、外部から自由に値を書き換えることができるため、不用意に変更されると不具合の原因となる可能性があります。
外部から直接変更されることを防ぎたい場合は、インスタンス変数を秘匿化し、アクセッサを通して参照、代入を行います。

アクセッサを作るには @property を使います。

class Person:
    def __init__(self, height, weight):
        self.age = 30
        self.height = height
        self.weight = weight
    @property
    def birthday(self):
        return self.__birthday
    @birthday.setter
    def birthday(self, birthday):
        self.__birthday = birthday

上記のプログラムでは、birthdayという変数に対してアクセッサを定義しています。
@propertyがついているメソッドが getter で、@変数名.setter がついているメソッドが setter です。

Pythonでは、変数名の先頭に、__ (アンダースコア2つ)がつくと、非公開の変数となります。
これを利用して、外部から直接変数にアクセスさせないようにし、不正な値を設定されようとした場合は、setterメソッドで事前にチェックすることで防ぐことができます。

上記のクラス定義をインスタンス化して、アクセッサを通して値を設定し、取得すると以下のようになります。

person = Person(170, 60)
person.birthday = "1990/01/01"
print(person.birthday) # -> 1990/01/01

getterのみ定義することで、読み取り専用のインスタンス変数を作ったりすることなどもできるようになります。

クラス変数

クラス自身が保持する変数をクラス変数と呼びます。
クラス名.変数名 または オブジェクト名.変数名 でアクセスすることができます。

class Person:
    name = "人間"

print(Person.name) # -> 人間
person = Person()
print(person.name) # -> 人間

クラス名.変数名 でのアクセスで値を書き換えると、インスタンス化したクラス変数も書き換わってしまう点には注意が必要です。

person = Person()
Person.name = "人間2"
print(Person.name) # -> 人間2
print(person.name) # -> 人間2

クラスメソッド

メソッドの第一引数に、クラスを受け取るメソッドをクラスメソッドと呼びます。
クラスメソッドを定義するには、@classmethod を付けます。
クラスメソッドの引数には、呼出し時に指定したクラス(下記例ではPersonクラス)を受け取ります。

class Person:
    @classmethod
    def say_classmethod(cls):
        print("classmethod")

上記のクラスメソッド say_classmethod を呼出すには、インスタンス化する必要はありません。

Person.say_classmethod() # -> classmethod

静的メソッド

クラスメソッドと同様にインスタンス化しなくても呼び出せるメソッドのもう1つに静的メソッド(staticメソッド)があります。
静的メソッドを定義するには、@staticmethod を付けます。
静的メソッドは決まった引数を受け取ることはありません。

class Person:
    @staticmethod
    def say_staticmethod():
        print("staticmethod")

上記の静的メソッド say_staticmethod を呼出すには、インスタンス化する必要はありません。

Person.say_staticmethod() # -> staticmethod

クラスの継承

クラスの継承とは、あるクラスを引き継いで新たなクラスを定義することです。
引き継ぎ元のクラスを親クラス(基底クラス、スーパークラス)と呼び、引き継ぎ先のクラスを子クラス(派生クラス、サブクラス)と呼びます。

子クラスを定義するには、括弧の中に親クラスを指定して、以下のように定義します。

class Child(Person):

子クラスは親クラスのメソッドや変数を継承しているため、そのまま呼出すことができます。

child = Child(70, 10)
child.walk() # -> 歩きます
print(child.height) # -> 70

親クラスが持つメソッドを同じメソッド名で処理を書き換える(オーバーライド)こともできます。
例えば、walkメソッドを以下のようにオーバーライドします。

class Child(Person):
    def walk(self):
        print("ハイハイします")

インスタンス化して、walkメソッドを呼出すと以下のようになります。

child = Child(70, 10)
child.walk() # -> ハイハイします

親クラスが持つメソッドは、super を使って呼出すことができます。

class Child(Person):
    def eat(self):
        super().eat()

const child = new Child(1, 70, 10);
child.eat(); // -> 食べます

Pythonでは、複数のクラスを継承する多重継承が可能です。
通常の継承と同様に、親クラスのメソッドを呼出すことができます。
ただし、同名のメソッドがある場合にどれが適用されるかという探索順位には注意が必要です。

良いプログラマになるにはクラス設計が重要

プログラマは単にプログラミングするだけではなく、設計ができることも重要です。

チームで効率よく開発を進めるには、どんなクラス設計、継承関係、クラス間連携とするのかは重要な要素です。

クラス分割をしたり、オブジェクト指向でプログラミングするのは難しいかもしれませんが、普段から目に見えるものがどんな関係があるか、どんな振る舞いを持っているのかを考えてみると良い訓練になると思います。

 

今回はPythonのクラスと継承についてまとめました。

以上、参考になれば幸いです。

コメント

タイトルとURLをコピーしました