<一覧に戻る

カプセル化とデータ隠蔽

オブジェクト指向プログラミング(OOP)におけるカプセル化データ隠蔽は、オブジェクトの内部状態を保護し、外部からの不正なアクセスや変更を防ぐための重要な概念です。このセクションでは、Pythonを用いてカプセル化とデータ隠蔽の基本的な考え方と実装方法を初心者にもわかりやすく解説します。

カプセル化とは?

カプセル化は、オブジェクトのデータ(属性)とそれに関連する操作(メソッド)を一つにまとめ、外部からのアクセスを制限する設計原則です。これにより、オブジェクトの内部状態を一貫性のあるものに保ち、システムの複雑さを管理しやすくします。

データ隠蔽とは?

データ隠蔽は、オブジェクトの内部データを外部から直接アクセスできないようにする手法です。これにより、データの不整合や不正な変更を防ぎます。Pythonでは、アクセス修飾子を使ってデータの可視性を制御します。

アクセス修飾子

Pythonには、主に以下の3種類のアクセス修飾子があります:

  1. パブリック(Public): デフォルトで全ての場所からアクセス可能。
  2. プロテクテッド(Protected): アンダースコア1つ(_)で始まる属性で、同じクラスやサブクラスからアクセス可能。
  3. プライベート(Private): アンダースコア2つ(__)で始まる属性で、クラス外からのアクセスを制限。

Pythonでのカプセル化の実装

パブリック属性

パブリック属性は、どこからでもアクセス可能です。以下の例では、nameageがパブリック属性です。

class Person:
    def __init__(self, name, age):
        self.name = name  # パブリック属性
        self.age = age    # パブリック属性

    def greet(self):
        print(f"こんにちは、私の名前は{self.name}です。年齢は{self.age}歳です。")
# オブジェクトの生成
person = Person("太郎", 25)

# パブリック属性へのアクセス
print(person.name)  # 出力: 太郎
print(person.age)   # 出力: 25

# パブリック属性の変更
person.age = 26
print(person.age)   # 出力: 26

プロテクテッド属性

プロテクテッド属性は、アンダースコア1つ(_)を属性名の前に付けて定義します。これは、プログラマに対して「この属性は内部で使用するものです。直接アクセスしないでください。」という合図です。

class Employee:
    def __init__(self, name, salary):
        self.name = name          # パブリック属性
        self._salary = salary     # プロテクテッド属性

    def get_salary(self):
        return self._salary

    def set_salary(self, amount):
        if amount > 0:
            self._salary = amount
        else:
            print("給与は正の数でなければなりません。")
# オブジェクトの生成
employee = Employee("花子", 50000)

# プロテクテッド属性へのアクセス(非推奨)
print(employee._salary)  # 出力: 50000

# メソッドを通じたアクセス
print(employee.get_salary())  # 出力: 50000

# メソッドを通じた属性の変更
employee.set_salary(55000)
print(employee.get_salary())  # 出力: 55000

employee.set_salary(-1000)    # 出力: 給与は正の数でなければなりません。

プライベート属性

プライベート属性は、アンダースコア2つ(__)を属性名の前に付けて定義します。これにより、名前マングリングが行われ、クラス外からの直接アクセスが困難になります。

class BankAccount:
    def __init__(self, owner, balance=0):
        self.owner = owner        # パブリック属性
        self.__balance = balance  # プライベート属性

    def deposit(self, amount):
        if amount > 0:
            self.__balance += amount
            print(f"{amount}円を入金しました。現在の残高は{self.__balance}円です。")
        else:
            print("入金額は正の数でなければなりません。")

    def withdraw(self, amount):
        if 0 < amount <= self.__balance:
            self.__balance -= amount
            print(f"{amount}円を引き出しました。現在の残高は{self.__balance}円です。")
        else:
            print("引き出し額が不正です。")

    def get_balance(self):
        return self.__balance
# オブジェクトの生成
account = BankAccount("佐藤", 10000)

# プライベート属性へのアクセス(エラーが発生)
# print(account.__balance)  # AttributeError: 'BankAccount' object has no attribute '__balance'

# メソッドを通じたアクセス
print(account.get_balance())  # 出力: 10000

# メソッドを通じた属性の変更
account.deposit(5000)          # 出力: 5000円を入金しました。現在の残高は15000円です。
account.withdraw(2000)         # 出力: 2000円を引き出しました。現在の残高は13000円です。
print(account.get_balance())   # 出力: 13000

名前マングリング

プライベート属性に対してPythonは名前マングリングを行います。属性名の前にクラス名が付加されるため、クラス外からは直接アクセスできませんが、完全には隠蔽されません。以下に例を示します。

class Secret:
    def __init__(self, data):
        self.__data = data  # プライベート属性

    def reveal(self):
        return self.__data
# オブジェクトの生成
secret = Secret("トップシークレット")

# プライベート属性へのアクセス(エラーが発生)
# print(secret.__data)  # AttributeError: 'Secret' object has no attribute '__data'

# 名前マングリングを利用してアクセス
print(secret._Secret__data)  # 出力: トップシークレット

# メソッドを通じたアクセス
print(secret.reveal())  # 出力: トップシークレット

まとめ

  • カプセル化は、オブジェクトのデータとメソッドを一つにまとめ、外部からのアクセスを制限する設計原則です。
  • データ隠蔽は、オブジェクトの内部データを外部から直接アクセスできないようにする手法です。
  • Pythonでは、アンダースコア1つ(_)でプロテクテッド属性を、アンダースコア2つ(__)でプライベート属性を表現します。
  • メソッドを通じて属性にアクセス・変更することで、データの一貫性と安全性を保つことができます。
  • 名前マングリングにより、プライベート属性へのアクセスをある程度防ぐことができますが、完全な隠蔽は保証されません。

実際にコードを書いて試すことで、カプセル化とデータ隠蔽の概念とその実装方法をより深く理解しましょう。

参考資料

出力結果: