Programación orientada a objetos en Python
La POO organiza un programa alrededor de objetos que poseen estado y ofrecen comportamiento mediante interfaces claras.
¿Qué es la programación orientada a objetos en Python?
La POO modela un sistema como objetos que colaboran. Cada objeto combina estado y operaciones válidas, facilitando responsabilidades claras en aplicaciones grandes.
Los cuatro principios fundamentales
- Encapsulación: reunir estado y comportamiento y controlar el acceso.
- Abstracción: mostrar una interfaz útil y ocultar detalles innecesarios.
- Herencia: especializar una clase solo ante una verdadera relación «es un».
- Polimorfismo: usar la misma operación con objetos distintos y comportamiento apropiado.
Diseño del ejemplo
- BankAccount posee el saldo y valida depósitos.
- SavingsAccount reutiliza el contrato base.
- SavingsAccount sobrescribe month_end para aplicar interés.
- El bucle usa todos los objetos mediante la misma interfaz.
Ejemplo básico
class BankAccount:
def __init__(self, owner, balance=0):
self.owner = owner
self._balance = float(balance)
@property
def balance(self):
return self._balance
def deposit(self, amount):
if amount <= 0:
raise ValueError("Deposit must be positive")
self._balance += amount
def month_end(self):
return "No interest"
class SavingsAccount(BankAccount):
def __init__(self, owner, balance, interest_rate):
super().__init__(owner, balance)
self.interest_rate = interest_rate
def month_end(self):
self._balance *= 1 + self.interest_rate
return "Interest applied"
accounts = [
BankAccount("Ada", 100),
SavingsAccount("Lin", 200, 0.05),
]
accounts[0].deposit(50)
for account in accounts:
status = account.month_end()
print(f"{account.owner}: {account.balance:.2f} ({status})")
Resultado esperado
Ada: 150.00 (No interest)
Lin: 210.00 (Interest applied)
Los cuatro principios de POO en la práctica
Estos ejemplos muestran cómo Python aplica encapsulación, abstracción, herencia y polimorfismo en código cotidiano.
Encapsulación
reunir estado y comportamiento y controlar el acceso.
class BankAccount:
def __init__(self, balance=0):
# Double underscores prevent accidental direct access.
self.__balance = balance
@property
def balance(self):
# Expose read access without exposing mutation.
return self.__balance
def deposit(self, amount):
# Keep validation next to the state it protects.
if amount <= 0:
raise ValueError("Amount must be positive")
self.__balance += amount
account = BankAccount(100)
account.deposit(50)
print(account.balance) # 150
Abstracción
mostrar una interfaz útil y ocultar detalles innecesarios.
from abc import ABC, abstractmethod
class PaymentMethod(ABC):
@abstractmethod
def pay(self, amount):
# Callers know what pay does, not how each provider does it.
pass
class CreditCard(PaymentMethod):
def pay(self, amount):
# The concrete class hides its payment implementation.
return f"Paid ${amount:.2f} by card"
payment = CreditCard()
print(payment.pay(25))
Herencia
especializar una clase solo ante una verdadera relación «es un».
class Employee:
def __init__(self, name):
self.name = name
def describe(self):
return self.name
class Developer(Employee):
def __init__(self, name, language):
# Reuse initialization from the parent class.
super().__init__(name)
self.language = language
def describe(self):
# Extend inherited behavior instead of duplicating it.
return f"{super().describe()} writes {self.language}"
print(Developer("Ada", "Python").describe())
Polimorfismo
usar la misma operación con objetos distintos y comportamiento apropiado.
class EmailNotification:
def send(self, message):
return f"Email: {message}"
class SmsNotification:
def send(self, message):
return f"SMS: {message}"
def notify(channels, message):
for channel in channels:
# The same call selects behavior from each concrete object.
print(channel.send(message))
channels = [EmailNotification(), SmsNotification()]
notify(channels, "Order shipped")
Cómo funciona
BankAccount encapsula el saldo. SavingsAccount hereda la interfaz y sobrescribe month_end. El bucle trata ambos objetos igual y Python elige el método adecuado en tiempo de ejecución.
Cambia los valores y ejecuta el programa en el compilador Python online de CodeUtility sin instalar Python.
Ejercicios prácticos
Modifica las entradas y prueba casos límite antes de usar conjuntos de datos mayores.
- Predice la salida antes de ejecutar.
- Controla entradas vacías o no válidas.
- Extrae la lógica a una función y añade pruebas.