Python

【Python 9】クラス

環境

macOS Big Sur
Python3.8

組み込み型について

これまで見てきた数値や文字列・コンテナといった「組み込み型」のデータには、「メソッド」という機能が型ごとに付属されています。

このメソッドを使用することで、より簡便に多様な処理を実行することができます。

メソッドは「データ.メソッド名()」とすることで、呼び出すことができます。

メソッドの呼び出し

データ.メソッド名(引数1の値, 引数2の値, …)

# メソッドの例。
>>> list = [1, 2, 3]

# 「append()メソッド」は、リストの末尾に要素を追加します。
>>> list.append(4) 
>>> list
[1, 2, 3, 4]

# 「pop()メソッド」は、リストから要素を取り出します。
# 引数でインデックスを指定することもできます。
# 指定しなければ末尾の要素を取り出します。
>>> list.pop()
4
>>> list
[1, 2, 3]

 

より広い表現として、「型」を「クラス」「データそのもの」を「オブジェクト」といいます。すでに用意されたクラスを組み込み型といいますが、クラス自体を独自に定義することもできます。

次の項から、クラスやオブジェクトの考え方を整理し、独自クラスの実装方法を説明していきます。

オブジェクトとクラス

「オブジェクト」とは、データとメソッド(データの種類に応じて用意されている関数)をひとまとめにしたものをいいます。

「クラス」とは、オブジェクトの仕様を定義した設計図のことを言います。そして、クラスから生成されたオブジェクトのことを「インスタンス」といいます。

「class文」を使用することで、クラスを定義することができます。クラス名は基本的に「大文字で始まる英単語」(「CamelCase」)を使用します。

クラスの定義

class クラス名:
    クラスの内容

クラスを呼び出すことで、インスタンスが生成できます。クラスの呼び出しは関数と同じ記法です。

インスタンスの生成

変数名 = クラス名()

# クラスの定義。
class MyClass:
    pass  # passは何も処理をしない命令です。


# インスタンスの生成。
i = MyClass()

 

クラスは「属性(アトリビュート)」として、変数とメソッドを持つことができます。

属性(変数)

クラスが持つ変数には、「クラス変数」「インスタンス変数」があります。

「クラス変数」はクラスの全インスタンスが共有する変数です。クラス定義文の直下で「変数名 = 値」として定義します。

クラス変数をクラスの外やメソッドから呼び出す場合は、「クラス名.クラス変数名」とします。値を代入することで、クラス変数を再定義することもできます。また、新しいクラス変数名を指定することで、新規にクラス変数を定義することもできます。

「インスタンス変数」はインスタンス固有の変数です。後述するメソッド内で「self.変数名 = 値」として定義します。このselfはインスタンス自身を表しています。

インスタンス変数をクラスの外から呼び出す場合は、「インスタンス名.インスタンス変数名」とします。値を代入することで、インスタンス変数を再定義することもできます。また、新しいインスタンス変数名を指定することで、新規にインスタンス変数を定義することもできます。

「インスタンス名.クラス変数名」(メソッド内では「self.クラス変数名」)とすることで、インスタンスを経由してクラス変数を呼び出すこともできますが、この方法は推奨されていません。

なお、同一クラス内で、同じ名前のクラス変数とインスタンス変数を定義することもできます。この場合、「インスタンス名.クラス変数名」としたつもりでも同名のインスタンス変数が優先されるため、クラス変数の参照はできません。

このように、インスタンスから変数を呼び出す場合、まずはインスタンス変数を探し、見つからない場合にクラス変数を探しにいきます。

※「クラス名.インスタンス変数名」によるインスタンス変数の呼び出しはできません。

# クラスの定義。
class MyClass:
    a = 1  # クラス変数の定義。

    # メソッドの定義。後述します。
    def __init__(self):
        self.b = 2  # インスタンス変数の定義。
        MyClass.c = 3  # 「クラス名.クラス変数名」で新規にクラス変数を定義できます。


print(MyClass.a)  # 「クラス名.クラス変数名」でクラス変数を呼び出せます。

i = MyClass()  # インスタンスの生成。
print(i.b)  # 「インスタンス名.インスタンス変数名」でインスタンス変数を呼び出せます。

i.d = 4  # 新規インスタンス変数の定義。
print(i.d)


# 実行結果
1
2
4

 

属性(メソッド)

クラス定義では、「def文」を使用することでインスタンスに属した関数(これを「メソッド」といいます。)を定義することができます。

関数の定義と同様ですが、第一引数には「self」を指定する必要があります。

メソッドは「インスタンス名.メソッド名()」で呼び出すことができます。なお、引数selfには自動的にインスタンス自体が渡されるため、呼び出す際は引数selfの値は省略します。(メソッド定義時に同一クラス内の別メソッドを呼び出すことも可能です。その際は、「self.呼び出すメソッド名()」とします。)

インスタンス生成時に自動的に呼び出されるメソッド(これを「初期化メソッド」といいます。)を定義することもできます。

初期化メソッド名は「__init__()」とします。初期化メソッドでself以外の引数を設定した場合、実引数はインスタンス生成時に指定します。

# クラスの定義。
class MyClass:

    # 初期化メソッドの定義。
    def __init__(self, a):
        self.a = a  # インスタンス変数aの定義。
    
    # メソッドの定義。
    def method(self, b):
        self.b = b  # インスタンス変数bの定義。
        return self.a * self.b


# インスタンスの生成。
i = MyClass(10)  # インスタンス変数a=10で初期化します。

# メソッドの呼び出し。
print(i.method(20))


# 実行結果
200

 

カプセル化

クラス定義の外からでも、「インスタンス名.インスタンス変数名」と指定することで、インスタンス変数を自由に変更することができます。クラス変数も同様です。

しかし、変更した結果、クラス定義時に意図していないエラー(数値として処理すべきアトリビュートに文字列を代入してしまう等。)を引き起こしてしまうこともあります。

クラス属性の外部利用を、以下の方法により制限することを「カプセル化」(encupsulation)といいます。

カプセル化の方法
  1. 名前の前に「_(アンダースコア)」がついている場合は、「クラス内部だけで利用するためにある」というルールがあります。
  2. 名前の前に「__(アンダースコア2つ)」がついている場合は、アクセスできません。

特殊メソッド

初期化メソッド「__init__()」のように、前後にアンダースコアが2つ付いたメソッドを「特殊メソッド」といいます。

特殊メソッドを使用することで特殊な構文(演算子を使った処理等)に対する特定の処理を実装することができます。

特殊メソッドについては、公式ドキュメントを参照してください。

公式ドキュメント(特殊メソッド)はこちら

継承

あるクラスを雛形にして別のクラスを作ることを「継承」と言います。

雛形となる元のクラスを「スーパークラス」、スーパークラスを元に作られた別のクラスを「サブクラス」と言います。

クラスの継承

class サブクラス名(スーパークラス名):
    クラスの内容

スーパークラスのメソッドは、そのままサブクラスに引き継がれますが、改めて定義し直すことでメソッドの上書き(これを「オーバーライド」といいます。)をすることができます。

class MyClass:

    def __init__(self, a, b):
        self.a = a
        self.b = b

    def method(self):
        return self.a * self.b

# MyClassを継承するSubClassを定義します。
class SubClass(MyClass):

    # 初期化メソッドをオーバーライド。
    def __init__(self, c):
        self.a = self.b = c

        
i = SubClass(10)
print(i.method())


# 実行結果
100

 

super()関数

上記のプログラムでは、スーパークラスの初期化メソッドに変更を加えた場合、サブクラスの初期化メソッドには反映されず(スーパークラスの変更に合わせた調整が必要)、それが原因でエラーが発生することがあります。

「super()関数」を使用することで、スーパークラスのメソッドをそのまま呼び出すこともできます。

class MyClass:

    def __init__(self, a, b):
        self.a = a
        self.b = b

    def method(self):
        return self.a * self.b


class SubClass(MyClass):

    # 初期化メソッドをオーバーライド。
    # super()関数でスーパークラスのメソッドを呼び出します。
    def __init__(self, c):
        super().__init__(c, c)

        
i = SubClass(10)
print(i.method())


# 実行結果
100