初心者のためのpython入門

自分がつまづいたところやつまづきやすいところを中心に書いていきます。また、役に立つライブラリの紹介などをしていきます。

カプセル化[1]

カプセル化

Pythonオブジェクト指向のプログラムを自由に開発することができます。
しかし、そのためにインスタンスの属性を書き間違える、呼び出してはいけないはずの関数を呼び出すなどのミスをしてしまうことがあります。このようなミスを未然に防ぐためにカプセル化という概念があります。
簡単に言うと、カプセル化は属性の読み書きやメソッドの呼び出しを制限することです。また、カプセル化は、ミスを防ぐだけでなく、プログラムをより可読性の高いものにすることができます。

アクセス制御

属性へのアクセスや関数の呼び出しなどを制限することをアクセス制御と言います。

アクセス制御のないクラス

まずは、これまで説明したことを利用してクラスを定義しましょう。

#hero.py
class Hero():
    def __init__(self, name):
        self.name = name

    def self_introduction(self):
        print("私の名前は勇者%sです。" % (self.name))

hero = Hero("ヨシヒコ")
hero.self_introduction()
hero.name = "ヨシピコ"
hero.self_introduction()
# 実行結果 (python hero.py)
私の名前は勇者ヨシヒコです。
私の名前は勇者ヨシピコです。

実行結果は上記のようになります。結果からわかるように、属性に直接アクセスして値を書き換えています。このように、Pythonでは基本的に全てのメソッドや属性が外部に公開されており、外部から直接アクセスできます。
しかし、属性の中には外部に公開したくないものや外部から直接操作したくないものもあります。そのような場合の対応策を次に説明します。

非公開属性

外部からの直接のアクセスを禁止するためには非公開属性を使用します。非公開属性は名前の先頭にダブルアンダースコア("__")を付けることにより定義できます。

プライベート変数とメンバ変数

メンバ変数(インスタンスに属する変数)の前にダブルアンダースコアを付けるとその変数はプライベート変数になります。プライベート変数には外部からアクセスすることができません。例を見てみましょう。

class Hero():
    def __init__(self, name, hp):
        self.name = name # 通常のメンバ変数

        self.__hp = hp # プライベート変数

    def self_introduction(self):
        print("私の名前は勇者%sです。" % (self.__name))

    def get_hp(self): # ゲッター
        return self.__hp

hero = Hero("ヨシヒコ", 10)
print(hero.name)
print(hero.get_hp())
print(hero.__hp) # アクセスできない
# 実行結果 (python hero.py)
ヨシヒコ
10
Traceback (most recent call last):
  File "hero.py", line 16, in <module>
    print(hero.__hp)
AttributeError: 'Hero' object has no attribute '__hp'

外部からアクセスしようとすると例外が発生しています。プライベート変数には、インスタンスメソッド内からはアクセスできます。そのため、プライベート変数にアクセスしたい場合はゲッターという関数を定義し、使用します。ゲッターとはプラベート変数を返り値にする関数です。また、プライベート変数に直接アクセスし、値を書き換えることはできません。プライベート変数に値を代入したいときは以下のようにセッターという関数を定義して使用します。

class Hero():
    def __init__(self, name, hp):
        self.name = name # 通常のメンバ変数

        self.__hp = hp # プライベート変数

    def self_introduction(self):
        print("私の名前は勇者%sです。" % (self.__name))

    def get_hp(self): # ゲッター
        return self.__hp

    def set_hp(self, new_hp): # セッター
        self.__hp = new_hp

hero = Hero("ヨシヒコ", 10)
print(hero.name)
print(hero.get_hp())
hero.set_hp(15)
print(hero.get_hp())
# 実行結果 (python hero.py)
ヨシヒコ
10
15

上記の結果のようにプライベート変数にアクセスし、書き換えることができました。

最後に

お疲れ様でした。次回はカプセル化の続きについて書きたいと思います。