Comentarios y Documentación
Aprende a documentar tu código Python correctamente utilizando comentarios, docstrings y buenas prácticas para crear programas mantenibles y comprensibles.
Cristian Escalante
Última actualización: 19 de mayo de 2025
Comentarios y Documentación en Python
La documentación adecuada es una parte esencial del desarrollo de software. Un código bien documentado es más fácil de entender, mantener y depurar, tanto para ti como para otros desarrolladores que puedan trabajar con tu código en el futuro. Python ofrece varias formas de documentar el código, desde simples comentarios hasta docstrings elaborados.
Comentarios en Python
Los comentarios son notas que se añaden al código para explicar su funcionamiento, pero que el intérprete de Python ignora durante la ejecución. Son útiles para aclarar secciones complejas, explicar decisiones de diseño o dejar notas para futuras revisiones.
Comentarios de una línea
En Python, los comentarios de una línea comienzan con el símbolo #
:
# Este es un comentario de una línea
x = 5 # También puedes añadir comentarios al final de una línea de código
Comentarios multilínea
Python no tiene un formato específico para comentarios multilínea, pero puedes usar varias líneas con #
o cadenas de texto que no se asignan a ninguna variable:
# Este es un comentario
# que abarca varias líneas
# utilizando el símbolo # en cada línea
"""
También puedes usar cadenas de texto de triple comilla
para crear bloques de texto que funcionen como comentarios.
Esto es útil para comentarios largos o documentación temporal.
"""
x = 10 # El código continúa aquí
Cuándo usar comentarios
Los comentarios deben usarse estratégicamente para mejorar la comprensión del código:
- Explicar código complejo: Cuando la lógica no es obvia a primera vista.
# Aplicamos el algoritmo de Fisher-Yates para mezclar la lista de manera eficiente
for i in range(len(lista) - 1, 0, -1):
j = random.randint(0, i)
lista[i], lista[j] = lista[j], lista[i]
- Documentar decisiones de diseño: Por qué se eligió una solución particular.
# Usamos un diccionario en lugar de una lista para búsquedas O(1)
usuarios = {}
- Marcar código temporal o problemas conocidos:
# TODO: Refactorizar esta función para mejorar el rendimiento
# FIXME: Esta función falla con valores negativos
# HACK: Solución temporal hasta que se actualice la API
Cuándo NO usar comentarios
Los comentarios no deben usarse para:
- Explicar código obvio: El código debe ser autoexplicativo cuando sea posible.
# Mal ejemplo
# Incrementa contador en 1
contador += 1
# Buen ejemplo (no necesita comentario)
contador += 1
- Mantener código obsoleto: Es mejor usar un sistema de control de versiones.
# No hagas esto
# función_antigua()
función_nueva()
- Compensar nombres poco descriptivos: Es mejor usar nombres claros.
# Mal ejemplo
x = y * 24 * 60 * 60 # Convertir días a segundos
# Mejor enfoque
segundos_por_dia = 24 * 60 * 60
segundos_totales = dias * segundos_por_dia
Docstrings: Documentación de código
Los docstrings (cadenas de documentación) son cadenas de texto especiales que se utilizan para documentar módulos, clases, métodos y funciones. A diferencia de los comentarios regulares, los docstrings son accesibles en tiempo de ejecución a través del atributo __doc__
.
Formato básico de docstrings
Los docstrings se definen utilizando triples comillas (simples o dobles) al principio de un módulo, clase, método o función:
def calcular_area_circulo(radio):
"""
Calcula el área de un círculo dado su radio.
Args:
radio (float): El radio del círculo.
Returns:
float: El área del círculo.
"""
import math
return math.pi * radio ** 2
# Acceder al docstring
print(calcular_area_circulo.__doc__)
Estilos de docstrings
Existen varios estilos de docstrings en Python. Los más comunes son:
1. Estilo Google
def dividir(a, b):
"""Divide dos números y devuelve el resultado.
Args:
a (int): El numerador.
b (int): El denominador.
Returns:
float: El resultado de la división.
Raises:
ZeroDivisionError: Si b es cero.
Examples:
>>> dividir(10, 2)
5.0
"""
return a / b
2. Estilo reStructuredText (reST)
Este estilo es utilizado por Sphinx, una herramienta popular para generar documentación:
def dividir(a, b):
"""Divide dos números y devuelve el resultado.
:param a: El numerador.
:type a: int
:param b: El denominador.
:type b: int
:return: El resultado de la división.
:rtype: float
:raises ZeroDivisionError: Si b es cero.
.. code-block:: python
>>> dividir(10, 2)
5.0
"""
return a / b
3. Estilo NumPy/SciPy
def dividir(a, b):
"""
Divide dos números y devuelve el resultado.
Parameters
----------
a : int
El numerador.
b : int
El denominador.
Returns
-------
float
El resultado de la división.
Raises
------
ZeroDivisionError
Si b es cero.
Examples
--------
>>> dividir(10, 2)
5.0
"""
return a / b
Docstrings para diferentes elementos
Docstring para módulos
Se coloca al principio del archivo:
"""
Módulo de utilidades matemáticas.
Este módulo proporciona funciones matemáticas básicas
como suma, resta, multiplicación y división.
"""
# Importaciones y código del módulo...
Docstring para clases
class Rectangulo:
"""
Clase que representa un rectángulo.
Esta clase permite crear rectángulos y calcular su área y perímetro.
Attributes:
ancho (float): El ancho del rectángulo.
alto (float): El alto del rectángulo.
"""
def __init__(self, ancho, alto):
"""
Inicializa un nuevo rectángulo.
Args:
ancho (float): El ancho del rectángulo.
alto (float): El alto del rectángulo.
"""
self.ancho = ancho
self.alto = alto
Docstring para métodos
def calcular_area(self):
"""
Calcula el área del rectángulo.
Returns:
float: El área del rectángulo (ancho * alto).
"""
return self.ancho * self.alto
Herramientas para documentación
Python ofrece varias herramientas integradas para trabajar con documentación:
La función help()
La función help()
muestra la documentación de un objeto:
help(print) # Muestra la documentación de la función print
help(str) # Muestra la documentación de la clase str
El atributo doc
Puedes acceder directamente al docstring de un objeto mediante su atributo __doc__
:
print(str.__doc__) # Muestra el docstring de la clase str
Herramientas externas
Existen varias herramientas para generar documentación automática a partir de docstrings:
- Sphinx: Una herramienta popular para generar documentación en varios formatos (HTML, PDF, etc.).
- pydoc: Una herramienta incluida en Python para generar documentación.
- MkDocs: Una herramienta para generar documentación en formato Markdown.
- pdoc: Una alternativa simple a pydoc.
Buenas prácticas de documentación
1. Sé consistente
Elige un estilo de docstring y úsalo de manera consistente en todo tu proyecto.
2. Documenta mientras programas
Es más fácil documentar el código mientras lo escribes que hacerlo después.
3. Actualiza la documentación
Mantén la documentación actualizada cuando cambies el código.
4. Documenta el "qué" y el "por qué", no el "cómo"
El código muestra cómo se hace algo. La documentación debe explicar qué hace y por qué.
# Mal ejemplo
# Este bucle recorre la lista y suma cada elemento
for item in lista:
total += item
# Buen ejemplo
# Calculamos la suma para determinar el promedio posteriormente
for item in lista:
total += item
5. Usa ejemplos
Los ejemplos son una forma efectiva de mostrar cómo usar tu código:
def fahrenheit_a_celsius(fahrenheit):
"""
Convierte grados Fahrenheit a Celsius.
Args:
fahrenheit (float): Temperatura en grados Fahrenheit.
Returns:
float: Temperatura en grados Celsius.
Examples:
>>> fahrenheit_a_celsius(32)
0.0
>>> fahrenheit_a_celsius(212)
100.0
"""
return (fahrenheit - 32) * 5 / 9
6. Incluye información sobre excepciones
Documenta las excepciones que tu función puede lanzar:
def obtener_elemento(lista, indice):
"""
Obtiene un elemento de la lista en el índice especificado.
Args:
lista (list): La lista de elementos.
indice (int): El índice del elemento a obtener.
Returns:
any: El elemento en el índice especificado.
Raises:
IndexError: Si el índice está fuera del rango de la lista.
TypeError: Si el índice no es un entero.
"""
return lista[indice]
Comentarios especiales
Python y muchas herramientas de desarrollo reconocen ciertos comentarios especiales:
TODO
Indica tareas pendientes:
# TODO: Implementar validación de entrada
# TODO(usuario): Optimizar algoritmo de búsqueda
FIXME
Indica problemas conocidos que deben solucionarse:
# FIXME: Esta función falla con valores negativos
HACK
Indica soluciones temporales o no ideales:
# HACK: Solución temporal hasta que se actualice la API
NOTE
Proporciona información adicional importante:
# NOTE: Esta función asume que la lista está ordenada
Documentación de proyectos
Además de documentar el código, es importante documentar el proyecto en su conjunto:
README
El archivo README es generalmente el primer documento que ven los usuarios:
# Mi Proyecto
Una breve descripción de lo que hace mi proyecto.
## Instalación
```bash
pip install mi-proyecto
Uso
import mi_proyecto
mi_proyecto.funcion_principal()
Características
- Característica 1
- Característica 2
Licencia
MIT
### Documentación de API
Para proyectos más grandes, es útil tener documentación específica de la API:
```markdown
# API Reference
## `module.function(param1, param2)`
Description of what the function does.
### Parameters:
- `param1` (type): Description of param1.
- `param2` (type): Description of param2.
### Returns:
- (return_type): Description of return value.
### Example:
```python
result = module.function("value1", "value2")
## Ejemplos prácticos
### Ejemplo 1: Función bien documentada
```python
def calcular_estadisticas(numeros):
"""
Calcula estadísticas básicas para una lista de números.
Esta función toma una lista de números y calcula varias
estadísticas descriptivas: mínimo, máximo, suma, promedio,
y desviación estándar.
Args:
numeros (list): Una lista de números (int o float).
Returns:
dict: Un diccionario con las estadísticas calculadas:
- 'min': El valor mínimo
- 'max': El valor máximo
- 'suma': La suma de todos los valores
- 'promedio': El promedio de los valores
- 'desviacion': La desviación estándar
Raises:
ValueError: Si la lista está vacía.
TypeError: Si la lista contiene elementos no numéricos.
Examples:
>>> calcular_estadisticas([1, 2, 3, 4, 5])
{'min': 1, 'max': 5, 'suma': 15, 'promedio': 3.0, 'desviacion': 1.4142}
"""
if not numeros:
raise ValueError("La lista no puede estar vacía")
# Verificar que todos los elementos son numéricos
if not all(isinstance(n, (int, float)) for n in numeros):
raise TypeError("Todos los elementos deben ser numéricos")
# Calcular estadísticas
minimo = min(numeros)
maximo = max(numeros)
suma = sum(numeros)
promedio = suma / len(numeros)
# Calcular desviación estándar
suma_cuadrados = sum((x - promedio) ** 2 for x in numeros)
desviacion = (suma_cuadrados / len(numeros)) ** 0.5
return {
'min': minimo,
'max': maximo,
'suma': suma,
'promedio': promedio,
'desviacion': round(desviacion, 4)
}
Ejemplo 2: Clase bien documentada
class CuentaBancaria:
"""
Clase que representa una cuenta bancaria simple.
Esta clase permite crear cuentas bancarias y realizar operaciones
básicas como depósitos, retiros y consultas de saldo.
Attributes:
titular (str): Nombre del titular de la cuenta.
saldo (float): Saldo actual de la cuenta.
numero_cuenta (str): Número único de la cuenta.
activa (bool): Indica si la cuenta está activa.
"""
def __init__(self, titular, saldo_inicial=0):
"""
Inicializa una nueva cuenta bancaria.
Args:
titular (str): Nombre del titular de la cuenta.
saldo_inicial (float, optional): Saldo inicial de la cuenta.
Por defecto es 0.
Raises:
ValueError: Si el saldo inicial es negativo.
TypeError: Si el titular no es una cadena de texto.
"""
if not isinstance(titular, str):
raise TypeError("El titular debe ser una cadena de texto")
if saldo_inicial < 0:
raise ValueError("El saldo inicial no puede ser negativo")
self.titular = titular
self.saldo = saldo_inicial
self.numero_cuenta = self._generar_numero_cuenta()
self.activa = True
def _generar_numero_cuenta(self):
"""
Genera un número de cuenta aleatorio.
Este es un método privado utilizado internamente.
Returns:
str: Un número de cuenta de 10 dígitos.
"""
import random
return ''.join(str(random.randint(0, 9)) for _ in range(10))
def depositar(self, cantidad):
"""
Deposita una cantidad en la cuenta.
Args:
cantidad (float): La cantidad a depositar.
Returns:
float: El nuevo saldo de la cuenta.
Raises:
ValueError: Si la cantidad es negativa o cero.
RuntimeError: Si la cuenta no está activa.
"""
if not self.activa:
raise RuntimeError("No se puede depositar en una cuenta inactiva")
if cantidad <= 0:
raise ValueError("La cantidad a depositar debe ser positiva")
self.saldo += cantidad
return self.saldo
def retirar(self, cantidad):
"""
Retira una cantidad de la cuenta.
Args:
cantidad (float): La cantidad a retirar.
Returns:
float: El nuevo saldo de la cuenta.
Raises:
ValueError: Si la cantidad es negativa, cero o mayor que el saldo.
RuntimeError: Si la cuenta no está activa.
"""
if not self.activa:
raise RuntimeError("No se puede retirar de una cuenta inactiva")
if cantidad <= 0:
raise ValueError("La cantidad a retirar debe ser positiva")
if cantidad > self.saldo:
raise ValueError("Fondos insuficientes")
self.saldo -= cantidad
return self.saldo
def consultar_saldo(self):
"""
Consulta el saldo actual de la cuenta.
Returns:
float: El saldo actual de la cuenta.
Raises:
RuntimeError: Si la cuenta no está activa.
"""
if not self.activa:
raise RuntimeError("No se puede consultar una cuenta inactiva")
return self.saldo
def cerrar_cuenta(self):
"""
Cierra la cuenta bancaria.
Una cuenta cerrada no permite realizar operaciones.
Returns:
bool: True si la cuenta se cerró correctamente.
Raises:
RuntimeError: Si la cuenta ya está inactiva.
"""
if not self.activa:
raise RuntimeError("La cuenta ya está inactiva")
self.activa = False
return True
def __str__(self):
"""
Devuelve una representación en cadena de la cuenta.
Returns:
str: Una cadena con información de la cuenta.
"""
estado = "activa" if self.activa else "inactiva"
return f"Cuenta {self.numero_cuenta} de {self.titular}: ${self.saldo:.2f} ({estado})"
Ejercicios prácticos
- Documenta una función que calcule el factorial de un número usando docstrings.
- Añade comentarios apropiados a un algoritmo de ordenamiento (como bubble sort o quicksort).
- Crea una clase
Libro
con atributos y métodos, y documéntala completamente usando el estilo de docstrings que prefieras. - Escribe un módulo simple con varias funciones y añade documentación a nivel de módulo y de función.
- Revisa un proyecto existente y mejora su documentación siguiendo las buenas prácticas aprendidas.
En la próxima lección, aprenderemos sobre estructuras de control condicionales en Python, que nos permitirán tomar decisiones en nuestros programas.