情報隠蔽
CoddyのPythonジャーニー「Object Oriented Programming」セクションの一部 — レッスン 30/64。
情報隠蔽は、オブジェクトのコンポーネントへの直接アクセスを制限し、すべての相互作用が適切に定義されたインターフェースを介して行われることを要求します。これにより、内部データが不正なアクセスから保護されます。
以下は、異なるレベルの情報隠蔽を持つクラスの例です:
class BankAccount:
def __init__(self, owner, initial_balance):
self.owner = owner # 公開 (Public) - 直接アクセス可能
self._balance = initial_balance # 保護 (Protected) - 内部利用
self.__account_number = "ACC123456" # 非公開 (Private) - 外部から隠蔽隠蔽されたデータへの制御されたアクセスを提供するメソッドを追加します:
class BankAccount:
def __init__(self, owner, initial_balance):
self.owner = owner
self._balance = initial_balance
self.__account_number = "ACC123456"
def deposit(self, amount):
if amount > 0:
self._balance += amount
return True
return False
def withdraw(self, amount):
if amount > 0 and amount <= self._balance:
self._balance -= amount
return True
return False
def get_balance(self):
return self._balance
def get_account_info(self):
# プライベートデータの一部を安全に表示する方法
return f"Owner: {self.owner}, Account: ***{self.__account_number[-4:]}"公開インターフェースを介してクラスを使用します:
account = BankAccount("Alice", 1000)公開データに直接アクセスする:
print(account.owner) # Alice - 公開アクセスOK保護されたデータには、制御されたメソッドを使用してください:
print(account.get_balance()) # 1000 - 制御されたアクセス
account.deposit(500)
print(account.get_balance()) # 1500 - 残高が安全に変更されました隠されたデータへのアクセスを試みます:
print(account.get_account_info()) # 所有者: Alice, アカウント: ***3456
# print(account.__account_number) # AttributeError - 隠されていますプライベート属性は名前修飾(name-mangling)されますが、技術的にはまだアクセス可能です:
# これは動作しますが、情報の隠蔽に違反します:
print(account._BankAccount__account_number) # ACC123456出力:
Alice
1000
1500
Owner: Alice, Account: ***3456
ACC123456重要なポイント:情報隠蔽は、内部データを private または protected に設定し、public メソッドを通じて制御されたアクセスを提供することで、データを保護します。これにより、機密データの直接的な操作を防ぎ、アクセスメソッド内でのバリデーションを通じてデータの整合性を保証します。
チャレンジ
中級このチャレンジでは、ソリューションを検証するための包括的なテストを備えた、安全なメッセージングシステムを実装します。
情報隠蔽の原則に従って SecureMessenger クラスを実装するために、securemessenger.py を編集する必要があります。ファイルには、実装のガイドとなる詳細な TODO コメントが含まれています。
主な要件は以下の通りです:
- 資格情報とメッセージの適切なカプセル化
- メッセージ操作を許可する前の認証
- ログイン試行の追跡によるセキュリティ監視
- TODO で指定された通りの正確なリターンメッセージ
チートシート
情報隠蔽は、アクセス修飾子を通じてオブジェクトのコンポーネントへの直接アクセスを制限します。
public- 直接アクセス可能(アンダースコアなし)_protected- 内部利用(アンダースコア1つ)__private- 外部から隠蔽(アンダースコア2つ)
class BankAccount:
def __init__(self, owner, initial_balance):
self.owner = owner # 公開 (Public)
self._balance = initial_balance # 保護 (Protected)
self.__account_number = "ACC123456" # 非公開 (Private)公開メソッドを通じて、制御されたアクセスを提供します。
def get_balance(self):
return self._balance
def deposit(self, amount):
if amount > 0:
self._balance += amount
return True
return False非公開属性は名前修飾(name-mangling)されますが、依然としてアクセス可能です。
# 情報隠蔽に違反しますが、動作します:
print(account._BankAccount__account_number)自分で試してみよう
from securemessenger import SecureMessenger
# テストケースのハンドラ
test_case = input()
if test_case == "default_test":
# 元の問題からの標準テストケース
messenger = SecureMessenger("user1")
# ログイン前にメッセージの追加を試行
print(messenger.add_message("Hello World!"))
print(messenger.add_message("Secure Message"))
# 間違ったパスワードでログインを試行
print(messenger.login("wrong_pass"))
# 正しいパスワードでログイン
print(messenger.login("secure123"))
# ログイン成功後にメッセージを追加
print(messenger.add_message("Hello World!"))
print(messenger.add_message("Secure Message"))
# メッセージを取得
print(messenger.get_messages())
# ログイン試行回数を確認
print(messenger.get_login_attempts())
elif test_case == "custom_password":
# カスタムパスワードでのテスト
messenger = SecureMessenger("admin", "admin123")
print(messenger.login("wrong_password"))
print(messenger.login("admin123"))
print(messenger.get_login_attempts())
elif test_case == "multiple_login_attempts":
# 複数回のログイン試行のテスト
messenger = SecureMessenger("user2")
print(messenger.login("attempt1"))
print(messenger.login("attempt2"))
print(messenger.login("attempt3"))
print(messenger.login("secure123"))
print(messenger.get_login_attempts())
elif test_case == "message_management":
# メッセージ管理のテスト
messenger = SecureMessenger("user3")
print(messenger.login("secure123"))
# 複数のメッセージを追加
messages = ["Message 1", "Message 2", "Message 3", "Message 4", "Message 5"]
for msg in messages:
print(messenger.add_message(msg))
# すべてのメッセージを検証
print(messenger.get_messages())
elif test_case == "empty_messages":
# メッセージが空の場合のテスト
messenger = SecureMessenger("user4")
print(messenger.login("secure123"))
print(messenger.get_messages())
elif test_case == "access_without_login":
# ログインなしでのアクセスのテスト
messenger = SecureMessenger("user5")
print(messenger.add_message("Unauthorized message"))
print(messenger.get_messages())
elif test_case == "attribute_privacy":
# 属性のプライバシーのテスト
messenger = SecureMessenger("user6")
# 公開属性
print(f"Public username: {messenger.username}")
# 非公開属性 - これらは AttributeError を発生させるはずです
try:
print(messenger.__password)
except AttributeError as e:
print("Password is private: AttributeError")
try:
print(messenger.__messages)
except AttributeError as e:
print("Messages are private: AttributeError")
try:
print(messenger.__login_attempts)
except AttributeError as e:
print("Login attempts are private: AttributeError")
try:
print(messenger.__is_logged_in)
except AttributeError as e:
print("Login status is private: AttributeError")
elif test_case == "login_logout_sequence":
# このテストでは、logoutメソッドでクラスを拡張する必要があります
# テスト目的で、ログアウト機能を備えたサブクラスを作成します
class ExtendedMessenger(SecureMessenger):
def logout(self):
self._SecureMessenger__is_logged_in = False
return "Logged out successfully"
messenger = ExtendedMessenger("user7")
print(messenger.login("secure123"))
print(messenger.add_message("Test message"))
print(messenger.get_messages())
print(messenger.logout())
print(messenger.get_messages())
elif test_case == "stress_test":
# 大量のメッセージによる負荷テスト
messenger = SecureMessenger("user8")
print(messenger.login("secure123"))
# 100件のメッセージを追加
for i in range(1, 101):
messenger.add_message(f"Message {i}")
# メッセージ数を確認
messages = messenger.get_messages()
newline_char = '\n' # 改行文字を変数に格納
message_count = len(messages.split(newline_char))
print(f"Added 100 messages. Retrieved {message_count} messages.")このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。