オブジェクト指向プログラミング(OOP)におけるカプセル化とデータ隠蔽は、オブジェクトの内部状態を保護し、外部からの不正なアクセスや変更を防ぐための重要な概念です。このセクションでは、Pythonを用いてカプセル化とデータ隠蔽の基本的な考え方と実装方法を初心者にもわかりやすく解説します。
カプセル化は、オブジェクトのデータ(属性)とそれに関連する操作(メソッド)を一つにまとめ、外部からのアクセスを制限する設計原則です。これにより、オブジェクトの内部状態を一貫性のあるものに保ち、システムの複雑さを管理しやすくします。
データ隠蔽は、オブジェクトの内部データを外部から直接アクセスできないようにする手法です。これにより、データの不整合や不正な変更を防ぎます。Pythonでは、アクセス修飾子を使ってデータの可視性を制御します。
Pythonには、主に以下の3種類のアクセス修飾子があります:
_
)で始まる属性で、同じクラスやサブクラスからアクセス可能。__
)で始まる属性で、クラス外からのアクセスを制限。パブリック属性は、どこからでもアクセス可能です。以下の例では、name
とage
がパブリック属性です。
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()) # 出力: トップシークレット
_
)でプロテクテッド属性を、アンダースコア2つ(__
)でプライベート属性を表現します。実際にコードを書いて試すことで、カプセル化とデータ隠蔽の概念とその実装方法をより深く理解しましょう。