Menu
Coddy logo textTech

情報隠蔽

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 メソッドを通じて制御されたアクセスを提供することで、データを保護します。これにより、機密データの直接的な操作を防ぎ、アクセスメソッド内でのバリデーションを通じてデータの整合性を保証します。

challenge icon

チャレンジ

中級

このチャレンジでは、ソリューションを検証するための包括的なテストを備えた、安全なメッセージングシステムを実装します。

情報隠蔽の原則に従って 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.")
quiz icon腕試し

このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。

Object Oriented Programmingのすべてのレッスン