Encapsulamiento

 El encapsulamiento consiste en ocultar los detalles internos de una clase y exponer solo lo necesario.

Su objetivo es:

  • Proteger los datos

  • Evitar modificaciones indebidas

  • Controlar el acceso

  • Mantener la integridad del objeto

Python no tiene privacidad estricta como Java o C#, pero usa convenciones y mecanismos que cumplen la misma función.

1. Atributos públicos, protegidos y privados

Público

Accesible desde cualquier parte.

self.nombre

Protegido (convención)

Indica que no debería tocarse desde fuera.

self._saldo

Privado (name mangling)

Python renombra internamente el atributo para evitar accesos accidentales.

self.__saldo

2. Ejemplo básico de encapsulamiento

class Cuenta:
    def __init__(self, titular, saldo):
        self.titular = titular      # público
        self.__saldo = saldo        # privado

    def ver_saldo(self):
        return self.__saldo

    def ingresar(self, cantidad):
        if cantidad > 0:
            self.__saldo += cantidad

    def retirar(self, cantidad):
        if 0 < cantidad <= self.__saldo:
            self.__saldo -= cantidad

3. Getters y Setters (propiedades)

Python permite crear propiedades con @property, una forma elegante de controlar el acceso.

class Persona:
    def __init__(self, nombre):
        self._nombre = nombre

    @property
    def nombre(self):
        return self._nombre

    @nombre.setter
    def nombre(self, nuevo):
        if len(nuevo) < 2:
            raise ValueError("El nombre es demasiado corto")
        self._nombre = nuevo

Uso:

p = Persona("Ana")
print(p.nombre)
p.nombre = "Luis"

4. ¿Por qué usar encapsulamiento?

  • Evita estados inválidos

  • Permite validar datos antes de asignarlos

  • Facilita mantenimiento

  • Protege información sensible (contraseñas, saldos, etc.)

  • Permite cambiar la implementación interna sin romper el código externo

ACTIVIDAD PRÁCTICA: “Sistema de cuenta bancaria segura”

Objetivo: que tus alumnos practiquen atributos privados, getters/setters y validación.

Enunciado

Crea una clase CuentaBancaria con:

Atributos privados:

  • __titular

  • __saldo

  • __iban

Métodos:

  1. depositar(cantidad)

  2. retirar(cantidad)

  3. ver_saldo()

  4. Propiedad iban (solo lectura)

  5. Propiedad titular (lectura y escritura con validación)

Requisitos:

  • No permitir saldo negativo

  • No permitir nombres vacíos

  • No permitir depósitos o retiradas negativas

  • Mostrar mensajes claros

Después:

  • Crea una cuenta

  • Haz varios depósitos y retiradas

  • Intenta hacer operaciones inválidas para comprobar la protección

Solución propuesta

class CuentaBancaria:
    def __init__(self, titular, saldo, iban):
        self.titular = titular      # setter validará
        self.__saldo = saldo
        self.__iban = iban

    # --- TITULAR ---
    @property
    def titular(self):
        return self.__titular

    @titular.setter
    def titular(self, nuevo):
        if len(nuevo.strip()) < 2:
            raise ValueError("El nombre del titular es inválido.")
        self.__titular = nuevo

    # --- IBAN (solo lectura) ---
    @property
    def iban(self):
        return self.__iban

    # --- SALDO ---
    def ver_saldo(self):
        return self.__saldo

    def depositar(self, cantidad):
        if cantidad <= 0:
            raise ValueError("La cantidad debe ser positiva.")
        self.__saldo += cantidad

    def retirar(self, cantidad):
        if cantidad <= 0:
            raise ValueError("La cantidad debe ser positiva.")
        if cantidad > self.__saldo:
            raise ValueError("Saldo insuficiente.")
        self.__saldo -= cantidad


# --- PRUEBAS ---
cuenta = CuentaBancaria("Ana López", 500, "ES12 3456 7890 1234")

cuenta.depositar(200)
cuenta.retirar(100)

print("Titular:", cuenta.titular)
print("IBAN:", cuenta.iban)
print("Saldo:", cuenta.ver_saldo())

# Prueba de validación
try:
    cuenta.titular = ""
except ValueError as e:
    print("Error:", e)

Ejemplo de salida

Titular: Ana López
IBAN: ES12 3456 7890 1234
Saldo: 600
Error: El nombre del titular es inválido.