Skip to content

11. Programación Orientada a Objetos

🎯 11.1 ¿Qué es la POO y por qué se usa?

Section titled “🎯 11.1 ¿Qué es la POO y por qué se usa?”

La Programación Orientada a Objetos (POO) es un paradigma de programación que organiza el código en torno a “objetos” que representan entidades del mundo real o conceptos abstractos. Cada objeto combina datos (atributos) y comportamientos (métodos).

PrincipioDescripción
AbstracciónModelar entidades del mundo real en código
EncapsulamientoOcultar detalles internos, exponer solo lo necesario
HerenciaCrear nuevas clases basadas en clases existentes
PolimorfismoObjetos de diferentes clases responden a la misma interfaz
  • Reutilización: Código modular y reutilizable
  • Mantenibilidad: Cambios localizados, fácil de actualizar
  • Organización: Estructura clara y lógica
  • Modelado natural: Representa conceptos del mundo real
  • Escalabilidad: Facilita el crecimiento de proyectos
ConceptoDescripción
ClasePlantilla o molde para crear objetos
ObjetoInstancia específica de una clase
AtributoDatos que describen el objeto
MétodoFunciones que definen el comportamiento del objeto
POO vs Procedural
# PROGRAMACIÓN PROCEDURAL (sin POO)
nombre_perro = "Max"
edad_perro = 3
raza_perro = "Labrador"
def ladrar(nombre):
print(f"{nombre} dice: ¡Guau!")
ladrar(nombre_perro)
# PROGRAMACIÓN ORIENTADA A OBJETOS
class Perro:
def __init__(self, nombre, edad, raza):
self.nombre = nombre
self.edad = edad
self.raza = raza
def ladrar(self):
print(f"{self.nombre} dice: ¡Guau!")
# Crear objeto
mi_perro = Perro("Max", 3, "Labrador")
mi_perro.ladrar() # Max dice: ¡Guau!

🏗️ 11.2 Crear clases y objetos en Python

Section titled “🏗️ 11.2 Crear clases y objetos en Python”

Sintaxis:

class NombreClase:
# Cuerpo de la clase
pass

Sintaxis:

objeto = NombreClase()
ConvenciónDescripción
Nombres de clasesPascalCase (primera letra de cada palabra en mayúscula)
Nombres de objetossnake_case (minúsculas con guiones bajos)
IndentaciónEl cuerpo de la clase debe estar indentado
Clase básica
# Definir una clase simple
class Persona:
pass
# Crear objetos (instancias)
persona1 = Persona()
persona2 = Persona()
print(type(persona1)) # <class '__main__.Persona'>
print(persona1 == persona2) # False (objetos diferentes)

📊 11.3 Propiedades (atributos) y comportamientos (métodos)

Section titled “📊 11.3 Propiedades (atributos) y comportamientos (métodos)”

Los atributos son variables que pertenecen a un objeto y almacenan su estado.

Los métodos son funciones definidas dentro de una clase que describen el comportamiento del objeto. El primer parámetro siempre es self.

Atributos y métodos
class Perro:
def __init__(self, nombre, raza):
self.nombre = nombre # Atributo
self.raza = raza # Atributo
def ladrar(self): # Método
print(f"{self.nombre} dice: ¡Guau!")
def presentarse(self): # Método
print(f"Hola, soy {self.nombre} y soy un {self.raza}")
mi_perro = Perro("Max", "Labrador")
mi_perro.ladrar() # Max dice: ¡Guau!
mi_perro.presentarse() # Hola, soy Max y soy un Labrador

El método __init__() es el constructor de la clase. Se ejecuta automáticamente cuando se crea un nuevo objeto para inicializar sus atributos.

def __init__(self, parametros):
self.atributo = valor
__init__()
class Persona:
def __init__(self, nombre, edad):
self.nombre = nombre
self.edad = edad
persona = Persona("Ana", 25)
print(f"{persona.nombre} tiene {persona.edad} años")
Valores por defecto
class CuentaBancaria:
def __init__(self, titular, saldo=0):
self.titular = titular
self.saldo = saldo
def mostrar_saldo(self):
print(f"Saldo de {self.titular}: {self.saldo} USD")
cuenta1 = CuentaBancaria("Ana", 1000)
cuenta2 = CuentaBancaria("Carlos") # saldo = 0
cuenta1.mostrar_saldo() # Saldo de Ana: 1000 USD

self es una referencia al objeto actual. Permite acceder a atributos y métodos del objeto desde dentro de la clase.

El encapsulamiento oculta los detalles internos. En Python:

NivelSintaxisDescripción
PúblicoatributoAccesible desde cualquier lugar
Protegido_atributoConvención, no debería accederse externamente
Privado__atributoName mangling, difícil de acceder externamente
self
class Rectangulo:
def __init__(self, base, altura):
self.base = base
self.altura = altura
def calcular_area(self):
return self.base * self.altura
def mostrar_info(self):
area = self.calcular_area() # Usar self para llamar método
print(f"Área: {area}")
rect = Rectangulo(5, 3)
rect.mostrar_info() # Área: 15
Encapsulamiento
class CuentaBancaria:
def __init__(self, titular, saldo_inicial):
self.titular = titular
self.__saldo = saldo_inicial # Privado
def depositar(self, cantidad):
if cantidad > 0:
self.__saldo += cantidad
def obtener_saldo(self):
return self.__saldo
cuenta = CuentaBancaria("Ana", 1000)
cuenta.depositar(500)
print(cuenta.obtener_saldo()) # 1500

👨‍👩‍👧 11.6 Herencia y clases hijas

Section titled “👨‍👩‍👧 11.6 Herencia y clases hijas”

La herencia permite crear nuevas clases basadas en clases existentes, heredando sus atributos y métodos.

Sintaxis:

class ClaseHija(ClasePadre):
# Código adicional

La función super() permite acceder a métodos de la clase padre.

Herencia
class Animal:
def __init__(self, nombre):
self.nombre = nombre
def hacer_sonido(self):
print("El animal hace un sonido")
class Perro(Animal):
def hacer_sonido(self):
print(f"{self.nombre} dice: ¡Guau!")
class Gato(Animal):
def hacer_sonido(self):
print(f"{self.nombre} dice: ¡Miau!")
perro = Perro("Max")
gato = Gato("Luna")
perro.hacer_sonido() # Max dice: ¡Guau!
gato.hacer_sonido() # Luna dice: ¡Miau!
super()
class Vehiculo:
def __init__(self, marca, modelo):
self.marca = marca
self.modelo = modelo
class Coche(Vehiculo):
def __init__(self, marca, modelo, puertas):
super().__init__(marca, modelo)
self.puertas = puertas
coche = Coche("Toyota", "Corolla", 4)
print(f"{coche.marca} {coche.modelo} - {coche.puertas} puertas")

⚙️ 11.7 Métodos especiales: str(), len(), etc.

Section titled “⚙️ 11.7 Métodos especiales: str(), len(), etc.”

Los métodos especiales permiten personalizar el comportamiento de los objetos.

MétodoUsoDescripción
__str__()print(obj)Representación legible
__len__()len(obj)Longitud del objeto
__eq__()obj1 == obj2Comparación de igualdad
__add__()obj1 + obj2Suma de objetos
__str__()
class Libro:
def __init__(self, titulo, autor):
self.titulo = titulo
self.autor = autor
def __str__(self):
return f'"{self.titulo}" por {self.autor}'
libro = Libro("Python 101", "Ana García")
print(libro) # "Python 101" por Ana García
__len__()
class Playlist:
def __init__(self, nombre):
self.nombre = nombre
self.canciones = []
def agregar(self, cancion):
self.canciones.append(cancion)
def __len__(self):
return len(self.canciones)
playlist = Playlist("Favoritas")
playlist.agregar("Canción 1")
playlist.agregar("Canción 2")
print(len(playlist)) # 2

📐 11.8 Buenas prácticas al diseñar clases

Section titled “📐 11.8 Buenas prácticas al diseñar clases”
PrincipioDescripción
Responsabilidad únicaUna clase debe tener un solo propósito
EncapsulamientoOcultar detalles de implementación
Nombres descriptivosClases y métodos con nombres claros
DocumentaciónUsar docstrings para explicar el código
Clase bien diseñada
class CuentaBancaria:
"""Representa una cuenta bancaria con operaciones básicas."""
def __init__(self, titular, saldo_inicial=0):
"""Inicializa una nueva cuenta bancaria."""
self.titular = titular
self.__saldo = saldo_inicial
def depositar(self, cantidad):
"""Deposita dinero en la cuenta."""
if cantidad > 0:
self.__saldo += cantidad
return True
return False
def retirar(self, cantidad):
"""Retira dinero de la cuenta."""
if 0 < cantidad <= self.__saldo:
self.__saldo -= cantidad
return True
return False
def obtener_saldo(self):
"""Retorna el saldo actual."""
return self.__saldo
def __str__(self):
return f"Cuenta de {self.titular}: {self.__saldo:.2f} USD"
cuenta = CuentaBancaria("Ana García", 1000)
cuenta.depositar(500)
print(cuenta) # Cuenta de Ana García: 1500.00 USD

🐝