カプセル化について

5.2 カプセル化について

「5.1変数のアクセスを制限する」でもカプセル化について少し触れましたが、この節で詳しく説明していきます。
まずカプセル化とは以下の要件を満たすものになります。

カプセル化の要件

① インスタンス変数の隠蔽することでクラスの外から利用できなくする。
② インスタンス変数の値を取得・設定するメソッドを用意する。

カプセル化を行うことで、インスタンス変数への直接的なアクセスは禁止し、インスタンス変数の値を設定するメソッド(setterメソッド)や取得するメソッド(getterメソッド)を用意します。それによりインスタンス変数に対して決められた操作しかできないようにします。
このようなインスタンス変数へアクセスする「セッターメソッド」と「ゲッターメソッド」を総称してアクセサメソッドと呼びます。

ポイント

  • インスタンス変数をクラス外からのアクセスを制限し、専用の操作(メソッド)を用意することをカプセル化と呼ぶ。

カプセル化のメリット・デメリット

メリット
1 外部からインスタンス変数を変更されることにより誤作動を防げる。
2 専用のアクセサメソッドを利用することで、外部からの間違ったアクセスを未然に防ぐことができる。
3 使用者が内部構造を理解していなくても使用できる。

デメリット

メリット
1 ソースコードの記述量が増える。
2 内部構造を知っていないと修正が難しくなる。
3 熟練者で無い人が作成したクラスを使うのは信用性に欠ける。

カプセル化を行うことで多少のデメリットは出てきますが、Pythonプログラミングに精通していければ解決する問題です。プログラムを作成するうえでは不正なアクセスを防ぎ、専用の操作を介することで間違ったアクセスを未然に防ぐメリットの方がデメリットよりも重要になってきます。
オブジェクト指向プログラミングでは、このカプセル化の仕組みが大変重要な役割を担っていると言えます。

5.2.2 ゲッター(getter)メソッドの作成規則

ではカプセル化において必要なアクセサメソッドについて、どのように定義すれば良いのでしょうか。アクセサメソッドについて、インスタンス変数の値を取得するgetterメソッド、値を変更するsetterメソッドの2つが存在すると説明しましたが、まずはgetterメソッドの定義方法について確認していきましょう。

書式:getterメソッド

まずメソッドを定義する前の行に、「@property」というデコレータを設けます。
メソッドの名称には決まりはありませんが、参照元のインスタンス変数と近い名前にするのが一般的です。
中の処理は、参照したいインスタンス変数の値を返す戻り値だけを設定するので、「return self.インスタンス変数名」と記載します。
定義方法をまとめると以下の書式になります。

凡例:ゲッターメソッド

書式:getterメソッドでインスタンス変数の値を取得

またgetterメソッドを介してインスタンス変数の値を取得するには、インスタンスを生成し、「インスタンス名.ゲッター名」と記載することで取得できます。

通常、メソッドを実行する際には、「メソッド名()」と括弧()を付ける必要がありますが、デコレータの「@property」を介して定義されたメソッドを、インスタンスを介して実行する際には、括弧()を付ける必要はありません。

凡例:ゲッターメソッド

実行結果

	メモリ: 80
	

実行結果からアクセス制限されたインスタンス変数「__memory」の値が取得できたことがわかります。取得する際に用いた「getMemory」には括弧はありませんが、先ほど申したようにメソッドに過ぎません。
混合しないよう注意しましょう。

5.2.3 セッター(setter)メソッドの作成規則

続いてアクセス制限のかかったインスタンス変数の値を変更するsetterメソッドの定義方法について確認していきましょう。

書式:setterメソッド

まずメソッドを定義する前の行に、「@ゲッター名.setter」というデコレータを設けます。
getterと同様、メソッドの名称には決まりはありませんが、参照元のインスタンス変数と近い名前にするのが良いでしょう。
メソッド内の処理は、参照したいインスタンス変数の値を変更する必要があるので、「self.インスタンス変数 = 値」と記載します。

凡例:セッターメソッド

書式:setterメソッドでインスタンス変数の値を変更

ではsetterメソッドを介してアクセス制限されたインスタンス変数の値を変更するには、どうすれば良いのでしょうか?
値を変更するには、インスタンスを生成し、「インスタンス名.セッター名 = 値」と記載することで実現できます。

ゲッターと同様、セッターを実行する際にも括弧()を付ける必要はありません。

凡例:セッターメソッドでインスタンス変数の値を変更

実行結果

	メモリ: 120
	

実行結果からアクセス制限されたインスタンス変数「__memory」の値を変更できたことがわかります。

5.2.4 セッター・ゲッターを応用したプログラム

インスタンス変数によっては、代入されると困る値もあり、その場合、代入する値を制限しなければなりません。
「5.1.1インスタンス変数の値を書き換えるプログラム」では、本来0以上であるはずのメモリーに、マイナスの値が代入されてしまいました。
このようにインスタンス変数に代入する値を制限する場合、セッター内の処理を記述する際に、条件分岐を併用して記述されることが多いです。
以下で条件分岐を用いて、セッターのプログラムを確認していきましょう。

ソース・フォルダー: /Desktop/Python基礎講座
ファイル名: 第5章.ipynb
アクセスURL: http://localhost:8888/notebooks/Desktop/Python基礎講座/第5章.ipynb

    class Computer:

        def __init__(self,name='Windows',memory=80):
            self.name = name
            self.__memory = memory #アクセス制限を指定

        @property
        def getMemory(self):
            return self.__memory

        @getMemory.setter
        def setMemory(self,value):
            if value >= 100:
                self.__memory = value
            else:
                self.__memory = 100

    #インスタンスの生成
    com1 = Computer()
    com1.setMemory = -30
    #インスタンス変数へアクセス
    print('com1のメモリー:',com1.getMemory,’GB’)
	

実行結果

	com1のメモリー: 100 GB
	

解説

1~16行目でComputerクラスを定義しています。3~5行目でコンストラクタを定義しており、4、5行目ではインスタンス変数「name」と「__memory」が宣言してます。
「__memory」に関しては行頭文字に_(アンダースコア)が2つ付与されているため、クラスの外からはアクセスできませんが、7~9行目ではゲッター用のメソッド「getMemory」を定義しているため、getMemoryを介してインスタンス変数「__memory」にアクセスできます。

        @property
        def getMemory(self):
            return self.__memory
	

11~16行目では、セッター用のメソッド「setMemory」が定義されてます。こちらのメソッドでは、条件分岐が指定しており、引数valueに代入される値が100以上の時、そのままインスタンス変数「__memory」に引数の値が入りますが、それ以外(valueが100未満)の場合、「__memory」に100が代入される処理になってます。

    @getMemory.setter
    def setMemory(self,value):
        if value >= 100:
            self.__memory = value
        else:
            self.__memory = 100
	

19行目でComputerクラスからcom1という名称のインスタンスを生成し、20行目でcom1を介してsetMemoryメソッドを実行し、引数valueに「-30」を代入しましたが、valueの値が100未満であるため、「__memory」には100が代入されます。

    #インスタンスの生成
    com1 = Computer()
    com1.setMemory = -30
	

setMemoryメソッドを実行し、引数valueに「-30」を代入しましたが、valueの値が100未満であるため、「__memory」には100が代入されます。

図 5.2.1: アクセス制限

そのため22行目で、ゲッターメソッドであるgetMemoryを介して「__memory」の値を出力すると上記のような実行結果になります。

    print('com1のメモリー:',com1.getMemory,’GB’)
	

ポイント

  • ゲッターを使ってアクセス制限されたインスタンス変数の値を取得できる
  • セッターを使ったアクセス制限されたインスタンス変数の値を書き換えできる

NEXT>> 5.3 本章のまとめ