32
34

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

初学者のためのPython講座 オブジェクト指向編7 カプセル化

Last updated at Posted at 2019-06-10

カプセル化

オブジェクト指向の重要概念の一つがカプセル化です。カプセル化とは、プログラムの外部からの操作を制御し、プログラムの独立性を保つための仕組みです。

テレビのリモコンに例えると、ユーザーはリモコンの単純なボタン操作によって、チャンネルを変える、ボリュームを下げるなどの操作ができます。ユーザーは内部の複雑なプログラムや回路を意識する必要はなく、誤った操作も起こしにくくなります。また、ユーザーが好き勝手にプログラムを書き換えたり、内部の回路に触れて改造したり、といった故障の原因を未然に防ぎます。

このようにオブジェクトの内部構造を隠蔽し、公開されたインターフェースによって外部からの操作を制御する仕組みがカプセル化です。使える機能を制限することで、ユーザーはどの機能を使えばいいかが分かりやすく、内部のプログラムに干渉しない・させないことで、大規模なプログラムでも複雑にならず、安定性が担保されます。

アクセス制御 プライベートとパブリック

オブジェクト指向プログラミングにおけるカプセル化は、オブジェクトの内部を**プライベート(非公開)パブリック(公開)**に分けて設定することです。プライベートなデータやメソッドに外部から直接アクセスすることはできず、公開された専用のメソッドによってのみアクセス可能となります。

ただし、Pythonでは公式ドキュメントに**「データ隠蔽を補強するための機構はなにもありません」と記述されている通り、基本的にすべてのデータやメソッドは外部に公開**されており、プライベートなデータやメソッドは存在しません

そのかわり、慣習的な命名規則として、**"_"(アンダーバー)**から始まる変数名やメソッド名はプライベートとみなします。

【書式】慣習的な命名規則としてのプライベート化

_要素名  # 要素名の前にアンダーバーを1つつける

例えば、クラスの中で_fooのような名前の変数やメソッドがあった場合、それは**「クラスの設計側だけが使うものであり、外部からはそれを利用しない」という決まり**です。あくまでもそうみなす、というだけなのでアクセス自体は可能です。

しかし、それでは困る場合があります。そこで、**ネームマングリング(難号化)**という機能を利用します。

マングリングは要素名の前に**"__"(アンダーバー2つ)**をつけます。

【書式】ネームマングリングによるプライベート化

__要素名  # 要素名の前にアンダーバーを2つつける

これによってクラスの外部から隠蔽し、プライベート化することができます。(実際には、非推奨の方法でアクセスすることもできます。)

プログラムで確認してみましょう。

次のプログラムでは、クラス変数を参照して戻り値を返すhello()メソッドと、その戻り値をprint()関数で表示するprinthello()メソッドが定義されています。そして、3種類の方法でクラス変数へアクセスしています。

まずはプライベート化していない状態です。

class Sample:
    name = "Yamada"
    def hello(self):
        return "Hello! I'm " + self.name
    def printhello(self):
        print(self.hello())

a = Sample()
print(a.name)      # クラス変数nameを直接参照して表示
print(a.hello())   # hello()メソッドの戻り値を表示
a.printhello()     # printhello()メソッドを呼び出す

実行してみましょう。

Yamada
Hello! I'm Yamada
Hello! I'm Yamada

では、クラス変数nameをマングリングして、プライベート変数__nameにアクセスできるか試してみましょう。

class Sample:
    __name = "Yamada"    # プライベート変数で定義
    def hello(self):
        return "Hello! I'm " + self.__name
    def printhello(self):
        print(self.hello())

a = Sample()
print(a.__name)    # クラス変数__nameを直接参照して表示
print(a.hello())
a.printhello()

変数nameをプライベート変数__nameに変更しました。実行してみましょう。

Traceback (most recent call last):
   File "private_sample.py", line 10, in <module>
     print(a.__name)
 AttributeError: 'Sample' object has no attribute '__name'

10行目print(a.__name)の部分でAttributeError(属性エラー)__nameという属性はありません」というエラーが出ました。変数__nameは隠蔽されているため、参照できなかったようです。

では、メソッド内で__nameを参照するhello()メソッドはどうでしょうか?

エラーが出た10行目print(a.__name)の部分をコメントアウト("#"を付けてコメントにする)して確認しましょう。

class Sample:
    __name = "Yamada"    # プライベート変数で定義
    def hello(self):
        return "Hello! I'm " + self.__name
    def printhello(self):
        print(self.hello())

a = Sample()

# print(a.__name)    コメントアウト
print(a.hello())
a.printhello()

実行してみましょう。

Hello! I'm Yamada
Hello! I'm Yamada

プライベート変数を直接参照することはできませんが、メソッドを通せばアクセス可能です。

次は、hello()メソッドをプライベートメソッド__hello()に変えてみましょう。

class Sample:
    __name = "Yamada"    # プライベート変数で定義
    def __hello(self):   # プライベートメソッドで定義
        return "Hello! I'm " + self.__name
    def printhello(self):
        print(self.__hello())

a = Sample()

# print(a.__name)       コメントアウト
print(a.__hello())
a.printhello()

実行してみましょう。

Traceback (most recent call last):
  File "private_sample.py", line 13, in <module>
    print(a.__hello())
AttributeError: 'Sample' object has no attribute '__hello'

11行目print(a.__hello())の部分でエラーが出ました。__hello()メソッドが隠蔽されているため、アクセスできなかったようです。

では、先ほどと同様にエラーが出た11行目print(a.__hello())コメントアウトして、メソッド内で__hello()メソッドの戻り値を表示するprint_hello()メソッドのほうを確認しましょう。

class Sample:
    __name = "Yamada"    # プライベート変数で定義
    def __hello(self):   # プライベートメソッドで定義
        return "Hello! I'm " + self.__name
    def printhello(self):
        print(self.__hello())

a = Sample()

# print(a.__name)       コメントアウト
# print(a.__hello())    コメントアウト
a.printhello()

実行してみましょう。

Hello! I'm Yamada

print_hello()メソッドが実行できました。

このように、プライベート化によって変数やメソッドを隠蔽することで、外部からのアクセスを特定のメソッドに制限できました。

クラス内部の変数やメソッドをプライベートとパブリックに分けて適切に管理することで、クラスの保守性を高めることができます。しかし、クラスの保守だけがカプセル化の目的ではありません。次は、アクセス制御するメソッドについて掘り下げていきましょう。


初学者のためのPython講座 オブジェクト指向編1 オブジェクト指向とは
初学者のためのPython講座 オブジェクト指向編2 クラスとインスタンス
初学者のためのPython講座 オブジェクト指向編3 メソッド
初学者のためのPython講座 オブジェクト指向編4 初期化メソッド
初学者のためのPython講座 オブジェクト指向編5 クラスの継承
初学者のためのPython講座 オブジェクト指向編6 クラス変数とクラスメソッド
初学者のためのPython講座 オブジェクト指向編7 カプセル化

随時追加予定
次回「プロパティ」

32
34
9

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
32
34

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?