CON · Concepto 8 · Programación orientada a objetos

38.Encapsulamiento

Proteger los datos internos de un objeto para que solo se cambien a través de sus métodos, que verifican las reglas.

¿Qué es?

Encapsular es esconder los detalles internos de un objeto y dejar que el resto del programa lo use solo a través de sus métodos, que hacen cumplir las reglas.

Piensa en un cajero automático: no metes la mano en la caja del dinero; usas los botones (los métodos). El cajero revisa tu saldo antes de entregarte billetes. Si cualquiera pudiera tocar el saldo directamente, alguien podría ponerse un millón.

Sin y con encapsulamiento

Sin encapsular Con encapsulamiento
cuenta.saldo = -500 (nadie lo impide) cuenta.retirar(500) revisa que alcance
Cualquier parte del código cambia los datos Solo la clase decide cómo cambian
Un error puede aparecer lejos de su causa La validación está en un solo lugar

En Python

Python no prohíbe el acceso; usa convenciones:

Nombre Significado
saldo Público: úsalo libremente
_saldo Interno: «no lo toques desde fuera»
__saldo Python le cambia el nombre (name mangling) para dificultar el acceso accidental

Sintaxis (pseudocódigo / Python)

Pseudocódigo de diseño (no ejecutable en PSeInt)

Clase Cuenta
	Privado: saldo
	Metodo depositar(monto):
		Si monto > 0 Entonces saldo <- saldo + monto
	Metodo retirar(monto):
		Si monto <= saldo Entonces saldo <- saldo - monto
		SiNo Escribir "Saldo insuficiente"
	Metodo consultar():
		Devolver saldo
FinClase

Python con atributo interno y métodos

class Cuenta:
    def __init__(self, titular):
        self.titular = titular
        self._saldo = 0

    def depositar(self, monto):
        if monto <= 0:
            raise ValueError("El depósito debe ser positivo")
        self._saldo += monto

    def retirar(self, monto):
        if monto > self._saldo:
            raise ValueError("Saldo insuficiente")
        self._saldo -= monto

    @property
    def saldo(self):              # se lee como atributo, sin paréntesis
        return self._saldo

c = Cuenta("Ana")
c.depositar(500)
c.retirar(200)
print(c.saldo)
try:
    c.retirar(1000)
except ValueError as e:
    print("Error:", e)

Salida:

300
Error: Saldo insuficiente

Como saldo es una propiedad sin setter, c.saldo = 10000 produce AttributeError: solo se puede cambiar con depositar y retirar.

Ejemplo guiado

Problema: una clase Alumno cuya calificación siempre esté entre 0 y 10, aunque se asigne como atributo.

class Alumno:
    def __init__(self, nombre, calificacion):
        self.nombre = nombre
        self.calificacion = calificacion       # pasa por el setter

    @property
    def calificacion(self):
        return self._calificacion

    @calificacion.setter
    def calificacion(self, valor):
        if not 0 <= valor <= 10:
            raise ValueError(f"Calificación inválida: {valor}")
        self._calificacion = valor

ana = Alumno("Ana", 8.5)
print(ana.nombre, ana.calificacion)

ana.calificacion = 9.2                        # válido
print(ana.nombre, ana.calificacion)

try:
    ana.calificacion = 15                     # inválido
except ValueError as e:
    print("Rechazado:", e)

print(ana.nombre, ana.calificacion)           # no cambió

Salida esperada:

Ana 8.5
Ana 9.2
Rechazado: Calificación inválida: 15
Ana 9.2

Desde fuera parece un atributo normal, pero cada asignación pasa por la validación, incluida la del constructor.

Errores comunes

# ✗ Incorrecto: el setter se llama a sí mismo sin fin
class Termometro:
    @property
    def grados(self):
        return self.grados

    @grados.setter
    def grados(self, valor):
        self.grados = valor

t = Termometro()
t.grados = 20
RecursionError: maximum recursion depth exceeded

Buenas prácticas

  • Valida en un solo lugar: el setter o el método que modifica.
  • Usa _ para lo interno y no lo uses desde fuera de la clase.
  • Expón operaciones con sentido (retirar, inscribir) en lugar de dejar modificar los datos crudos.
  • Lanza ValueError cuando te pasen datos inválidos.
  • Propiedades de solo lectura para valores que no deben cambiarse desde fuera.

Material descargable

Aún no hay material descargable para este tema. Pronto habrá cuadernillos, manuales o laboratorios.

Referencias

© solutions_ · Fundamentos de programación · 38 Encapsulamiento