Menu
Coddy logo textTech

Ocultamiento de información

Parte de la sección Object Oriented Programming del Journey de Python de Coddy — lección 30 de 64.

El ocultamiento de información restringe el acceso directo a los componentes del objeto, requiriendo que todas las interacciones ocurran a través de interfaces bien definidas. Esto protege los datos internos del acceso no autorizado.

Aquí hay un ejemplo de una clase con diferentes niveles de ocultación de información:

class BankAccount:
    def __init__(self, owner, initial_balance):
        self.owner = owner                    # Público - se puede acceder directamente
        self._balance = initial_balance       # Protegido - uso interno
        self.__account_number = "ACC123456"   # Privado - oculto desde el exterior

Agrega métodos que proporcionen acceso controlado a los datos ocultos:

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):
        # Forma segura de mostrar datos privados parciales
        return f"Owner: {self.owner}, Account: ***{self.__account_number[-4:]}"

Usa la clase a través de su interfaz pública:

account = BankAccount("Alice", 1000)

Accede a los datos públicos directamente:

print(account.owner)  # Alice - acceso público OK

Usa métodos controlados para datos protegidos:

print(account.get_balance())  # 1000 - acceso controlado
account.deposit(500)
print(account.get_balance())  # 1500 - el saldo cambió de forma segura

Intenta acceder a los datos ocultos:

print(account.get_account_info())  # Propietario: Alice, Cuenta: ***3456
# print(account.__account_number)  # AttributeError - oculto

El atributo privado está sujeto a "name mangling" pero sigue siendo técnicamente accesible:

# Esto funciona pero viola la ocultación de información:
print(account._BankAccount__account_number)  # ACC123456

Salida:

Alice
1000
1500
Owner: Alice, Account: ***3456
ACC123456

Punto clave: La ocultación de información protege los datos internos al hacerlos privados o protegidos, y luego proporcionar acceso controlado a través de métodos públicos. Esto evita la manipulación directa de datos sensibles y garantiza la integridad de los datos mediante la validación en los métodos de acceso.

challenge icon

Desafío

Intermedio

En este desafío, implementarás un sistema de mensajería seguro con pruebas exhaustivas para validar tu solución.

Debes editar securemessenger.py para implementar la clase SecureMessenger siguiendo los principios de ocultación de información. El archivo contiene comentarios TODO detallados para guiar tu implementación.

Los requisitos clave incluyen:

  • Encapsulación adecuada de credenciales y mensajes
  • Autenticación antes de permitir operaciones de mensajes
  • Monitoreo de seguridad a través del seguimiento de intentos de inicio de sesión
  • Mensajes de retorno precisos según lo especificado en los TODOs

Hoja de referencia

El ocultamiento de información restringe el acceso directo a los componentes de un objeto a través de modificadores de acceso:

  • public - accesible directamente (sin guion bajo)
  • _protected - uso interno (un solo guion bajo)
  • __private - oculto desde el exterior (doble guion bajo)
class BankAccount:
    def __init__(self, owner, initial_balance):
        self.owner = owner                    # Público
        self._balance = initial_balance       # Protegido
        self.__account_number = "ACC123456"   # Privado

Proporcione acceso controlado a través de métodos públicos:

def get_balance(self):
    return self._balance

def deposit(self, amount):
    if amount > 0:
        self._balance += amount
        return True
    return False

Los atributos privados están sujetos a la deformación de nombres (name-mangling) pero siguen siendo accesibles:

# Viola el ocultamiento de información pero funciona:
print(account._BankAccount__account_number)

Pruébalo tú mismo

from securemessenger import SecureMessenger

# Manejador de casos de prueba
test_case = input()
if test_case == "default_test":
    # Caso de prueba estándar del problema original
    messenger = SecureMessenger("user1")
    
    # Intentar añadir mensajes antes de iniciar sesión
    print(messenger.add_message("Hello World!"))
    print(messenger.add_message("Secure Message"))
    
    # Intento de inicio de sesión con contraseña incorrecta
    print(messenger.login("wrong_pass"))
    
    # Inicio de sesión con contraseña correcta
    print(messenger.login("secure123"))
    
    # Añadir mensajes después de un inicio de sesión exitoso
    print(messenger.add_message("Hello World!"))
    print(messenger.add_message("Secure Message"))
    
    # Recuperar mensajes
    print(messenger.get_messages())
    
    # Verificar intentos de inicio de sesión
    print(messenger.get_login_attempts())
elif test_case == "custom_password":
    # Prueba con contraseña personalizada
    messenger = SecureMessenger("admin", "admin123")
    print(messenger.login("wrong_password"))
    print(messenger.login("admin123"))
    print(messenger.get_login_attempts())
elif test_case == "multiple_login_attempts":
    # Probar múltiples intentos de inicio de sesión
    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":
    # Probar la gestión de mensajes
    messenger = SecureMessenger("user3")
    print(messenger.login("secure123"))
    
    # Añadir múltiples mensajes
    messages = ["Message 1", "Message 2", "Message 3", "Message 4", "Message 5"]
    for msg in messages:
        print(messenger.add_message(msg))
    
    # Verificar todos los mensajes
    print(messenger.get_messages())
elif test_case == "empty_messages":
    # Probar caso de mensajes vacíos
    messenger = SecureMessenger("user4")
    print(messenger.login("secure123"))
    print(messenger.get_messages())
elif test_case == "access_without_login":
    # Probar acceso sin iniciar sesión
    messenger = SecureMessenger("user5")
    print(messenger.add_message("Unauthorized message"))
    print(messenger.get_messages())
elif test_case == "attribute_privacy":
    # Probar la privacidad de los atributos
    messenger = SecureMessenger("user6")
    
    # Atributo público
    print(f"Public username: {messenger.username}")
    
    # Atributos privados - estos deberían lanzar 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":
    # Esta prueba requiere extender la clase con un método de cierre de sesión
    # Para fines de prueba, crearemos una subclase con funcionalidad de cierre de sesión
    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":
    # Prueba de esfuerzo con muchos mensajes
    messenger = SecureMessenger("user8")
    print(messenger.login("secure123"))
    
    # Añadir 100 mensajes
    for i in range(1, 101):
        messenger.add_message(f"Message {i}")
    
    # Verificar el recuento de mensajes
    messages = messenger.get_messages()
    newline_char = '\n'  # Almacenar el carácter de nueva línea en una variable
    message_count = len(messages.split(newline_char))
    print(f"Added 100 messages. Retrieved {message_count} messages.")
quiz iconPonte a prueba

Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.

Todas las lecciones de Object Oriented Programming