📘Clase 3: OOP y Documentación Profesional📘#
🎯 Objetivos de la sesión#
Dominar la documentación de código con docstrings
Comprender los principios fundamentales de la Programación Orientada a Objetos (POO) en Python
Aprender a estructurar proyectos mediante modularización
Generar documentación profesional utilizando Sphinx
📄 Programación Orientada a Objetos en Python#
Documentación de funciones en Python#
def funcion(parametro1: int, parametro2: str) -> float:
"""Breve descripción de la función.
:param int parametro1: Descripción del parámetro 1
:param str parametro2: Descripción del parámetro 2
:return float: Descripción del valor retornado
:example:
>>> funcion(1, 2)
3
"""
# Código de la función
OOP - Conceptos fundamentales#
La Programación Orientada a Objetos es un paradigma que nos permite modelar el mundo real mediante objetos que tienen:
Atributos: características o propiedades de un objeto
Ejemplo: Un objeto Coche puede tener atributos como
marca
,modelo
,color
,año
Métodos: acciones o comportamientos que puede realizar un objeto
Ejemplo: El Coche puede tener métodos como
arrancar()
,frenar()
,acelerar()
Encapsulamiento: ocultación de datos internos y exposición controlada mediante interfaces
Protege la integridad de los datos de un objeto
En Python usamos convenciones como
_atributo
(protegido) y__atributo
(privado)
Herencia: mecanismo para crear nuevas clases a partir de clases existentes
Permite reutilizar código y establecer jerarquías
Ejemplo:
SUV
hereda deCoche
y añade características específicas
Polimorfismo: capacidad de objetos de distintas clases para responder al mismo método
Ejemplo: Diferentes vehículos pueden responder al método
arrancar()
de manera distinta
Definiendo clases en Python#
class Coche:
"""Clase para representar un coche."""
# Constructor
def __init__(self, marca: str, modelo: str, año: int) -> None:
"""Inicializa un nuevo objeto Coche.
:param marca: La marca del coche
:param modelo: El modelo del coche
:param año: El año de fabricación del coche
"""
self.marca = marca
self.modelo = modelo
self.año = año
self.encendido = False
self.velocidad = 0
def arrancar(self) -> bool:
"""Arranca el motor del coche.
:return: True si el coche arrancó correctamente, False si ya estaba encendido
"""
if not self.encendido:
self.encendido = True
print(f"{self.marca} {self.modelo} arrancado.")
return True
else:
print(f"{self.marca} {self.modelo} ya estaba encendido.")
return False
def acelerar(self, incremento: int) -> int:
"""Aumenta la velocidad del coche.
:param incremento: Cantidad en km/h a incrementar
:return: La nueva velocidad del coche
"""
if self.encendido:
self.velocidad += incremento
print(f"{self.marca} {self.modelo} acelerando a {self.velocidad} km/h.")
return self.velocidad
else:
print("No se puede acelerar un coche apagado.")
return 0
def __str__(self) -> str:
"""Representación en texto del coche.
:return: Cadena descriptiva del coche
"""
estado = "encendido" if self.encendido else "apagado"
return f"{self.marca} {self.modelo} ({self.año}) - {estado}, {self.velocidad} km/h"
Ejemplo de uso de la clase#
# Crear una instancia de la clase Coche
mi_coche = Coche("Toyota", "Corolla", 2023)
print(mi_coche) # Toyota Corolla (2023) - apagado, 0 km/h
# Usar los métodos
mi_coche.arrancar()
mi_coche.acelerar(20)
print(mi_coche) # Toyota Corolla (2023) - encendido, 20 km/h
# Crear otra instancia
otro_coche = Coche("Honda", "Civic", 2022)
print(otro_coche)
Herencia - Ejemplo#
class SUV(Coche):
"""Clase para representar un SUV, que hereda de Coche."""
def __init__(self, marca: str, modelo: str, año: int, traccion: str) -> None:
"""Inicializa un nuevo SUV.
:param marca: La marca del SUV
:param modelo: El modelo del SUV
:param año: El año de fabricación
:param traccion: Tipo de tracción (4x4, 4x2, AWD)
"""
# Llamada al constructor de la clase padre
super().__init__(marca, modelo, año)
self.traccion = traccion
self.modo_off_road = False
def activar_modo_off_road(self) -> bool:
"""Activa el modo todoterreno.
:return: True si se activó correctamente, False en caso contrario
"""
if self.encendido and self.traccion in ["4x4", "AWD"]:
self.modo_off_road = True
print(f"{self.marca} {self.modelo}: Modo off-road activado.")
return True
else:
print(f"No se puede activar el modo off-road.")
return False
def __str__(self) -> str:
"""Representación en texto del SUV.
:return: Cadena descriptiva del SUV
"""
# Reutilizamos el método de la clase padre y añadimos información
texto_base = super().__str__()
modo = "Modo off-road activado" if self.modo_off_road else "Modo normal"
return f"{texto_base}, Tracción: {self.traccion}, {modo}"
Atributos y métodos de clase#
class Vehiculo:
"""Clase para representar un vehículo genérico."""
# Atributo de clase (compartido por todas las instancias)
num_vehiculos = 0
def __init__(self, tipo: str) -> None:
"""Inicializa un nuevo vehículo.
:param tipo: Tipo de vehículo
"""
self.tipo = tipo
# Incrementamos el contador de clase
Vehiculo.num_vehiculos += 1
@classmethod
def obtener_total_vehiculos(cls) -> int:
"""Método de clase para obtener el número total de vehículos.
:return: Número total de vehículos creados
"""
return cls.num_vehiculos
@staticmethod
def validar_patente(patente: str) -> bool:
"""Método estático para validar un formato de patente.
:param patente: Patente a validar
:return: True si la patente tiene formato válido, False en caso contrario
"""
# Ejemplo básico: 3 letras seguidas de 3 números
import re
return bool(re.match(r'^[A-Z]{3}\d{3}$', patente))
Estructurando proyectos mediante modularización#
mi_paquete/
├── __init__.py # Convierte la carpeta en un paquete importable
├── modulo1.py # Módulo con funciones y clases relacionadas
├── modulo2.py # Otro módulo con funcionalidad específica
└── subpaquete/ # Subpaquete para organizar código relacionado
├── __init__.py
└── modulo3.py
📖 Documentación profesional con Sphinx#
Configuración básica de Sphinx#
# Instalar Sphinx
pip install sphinx sphinx_rtd_theme
# Iniciar un proyecto de documentación
mkdir docs
cd docs
sphinx-quickstart
El archivo conf.py
generado contiene la configuración de Sphinx:
# Configuración básica para un proyecto Python
extensions = [
'sphinx.ext.autodoc',
'sphinx.ext.viewcode',
'sphinx.ext.napoleon',
]
html_theme = 'sphinx_rtd_theme'
Generación de documentación desde docstrings#
# En docs/source/index.rst
.. automodule:: mi_paquete.modulo1
:members:
:undoc-members:
:show-inheritance:
Comandos para generar documentación#
# Generar HTML
sphinx-build -b html source/ build/html
# Generar PDF (requiere LaTeX)
sphinx-build -b latex source/ build/latex
cd build/latex
make
📋 Actividades prácticas#
Añade un nuevo método a la clase SuperTabla que permita calcular estadísticas descriptivas (media, mediana, desviación estándar) para columnas numéricas.
Crea un método para exportar la tabla a un archivo CSV.
Implementa un método para unir dos tablas (similar al join de SQL o pandas).
Documenta completamente tus métodos utilizando docstrings con formato
:param
y:return:
.Genera documentación HTML con Sphinx para tu módulo de tablas.
📚 Referencias y recursos adicionales#
Documentación oficial de Python sobre clases
Guía de estilo para docstrings
Documentación de Sphinx
Tutorial sobre creación de paquetes Python