Herramientas de usuario

Herramientas del sitio


informatica:programacion:cursos:programacion_desde_cero_con_python:biblioteca_estandar_y_aplicaciones_utiles

Biblioteca estándar y aplicaciones útiles

Biblioteca estándar y aplicaciones útiles: fechas, datos, texto, red y persistencia.

Este módulo forma parte del curso de programación desde cero con Python

El programa que reinventa la rueda

Imagina que necesitas calcular la edad de un usuario a partir de su fecha de nacimiento, validar un correo electrónico, descargar datos de una API o guardar registros en una base de datos. Podrías escribir todo desde cero: una función para parsear fechas, otra para validar correos con condicionales interminables, otra para manejar sockets HTTP… Sería un trabajo enorme, propenso a errores y difícil de mantener. La biblioteca estándar de Python ya resuelve esos problemas, de forma probada y documentada.

Conocer la biblioteca estándar es lo que distingue a un programador que resuelve problemas de uno que reinventa soluciones. Este módulo te presenta los módulos esenciales, con ejemplos prácticos y advertencias de seguridad, para que puedas construir aplicaciones útiles sin depender de decenas de bibliotecas externas.

5. Explicación paso a paso

5.1. `datetime`: fechas y horas

El módulo datetime proporciona clases para manipular fechas y horas. Las principales son date (año, mes, día), time (hora, minuto, segundo, microsegundo) y datetime (fecha y hora combinadas). timedelta representa una duración.

from datetime import datetime, date, timedelta, timezone
 
ahora = datetime.now()
hoy = date.today()
cumple = date(1990, 5, 20)
edad = hoy.year - cumple.year - ((hoy.month, hoy.day) < (cumple.month, cumple.day))
 
print(ahora)                         # 2026-10-31 12:34:56.789
print(cumple.strftime("%d/%m/%Y"))   # 20/05/1990
print(edad)                          # 36
 
# Aritmética con timedelta
manana = hoy + timedelta(days=1)
print(manana)

Objetos aware y naive: un objeto datetime es aware si incluye información de zona horaria (tzinfo), y naive si no la incluye. Para aplicaciones que cruzan zonas horarias, usa objetos aware con timezone.utc o zoneinfo.ZoneInfo.

ahora_utc = datetime.now(timezone.utc)
[PYTHON] datetime es la referencia para fechas y horas en Python. Para zonas horarias con nombres (por ejemplo, "Europe/Madrid"), usa el módulo zoneinfo (Python 3.9+), que implementa la base de datos IANA. La clase timezone solo representa desplazamientos fijos respecto a UTC.
[ERROR HABITUAL] Restar dos fechas naive que representan zonas horarias distintas produce resultados incorrectos. Si la aplicación maneja zonas horarias, usa siempre objetos aware.

5.2. `math` y `statistics`: matemáticas y estadísticas

math ofrece funciones matemáticas comunes: sqrt, ceil, floor, log, sin, cos, constantes como pi y e, y funciones de agregación como sumprod o dist.

[NOVEDAD 3.15] Python 3.15 añade el submódulo math.integer (PEP 791), que agrupa funciones matemáticas específicas para enteros, como gcd, lcm, isqrt, comb y perm. Estas funciones antes estaban en math, pero se han movido a math.integer para separar las operaciones de punto flotante de las enteras. Las versiones antiguas siguen funcionando por compatibilidad, pero el código nuevo debería usar math.integer.
from math import integer
print(integer.gcd(12, 18))  # 6

statistics calcula estadísticas descriptivas: mean, median, mode, stdev, variance, quantiles, etc. A diferencia de math, está pensado para analizar datos, no para funciones matemáticas individuales.

import statistics
 
datos = [10, 20, 30, 40, 50]
print(statistics.mean(datos))     # 30
print(statistics.median(datos))   # 30
print(statistics.stdev(datos))    # 15.81...
[PYTHON] statistics no pretende competir con NumPy o SciPy. Es adecuado para cálculos sencillos en scripts y aplicaciones pequeñas. Para análisis de datos a gran escala, usa bibliotecas especializadas.
[ERROR HABITUAL] Pasar datos con NaN a median, mode o quantiles produce resultados inesperados, porque NaN tiene una semántica de comparación peculiar. Elimina los NaN antes de llamar a estas funciones.

random y secrets: aleatoriedad

random genera números pseudoaleatorios para simulaciones, juegos y muestreo. No es criptográficamente seguro.

import random
 
print(random.randint(1, 10))          # Entero entre 1 y 10
print(random.choice(["a", "b", "c"])) # Elección aleatoria
random.shuffle(lista)                 # Mezcla in situ

secrets genera números y tokens criptográficamente seguros. Úsalo para contraseñas, tokens de sesión, URLs de restablecimiento y cualquier valor que deba ser impredecible.

import secrets
 
token = secrets.token_urlsafe(32)
contrasena = secrets.token_hex(16)
[SEGURIDAD] No uses random para generar contraseñas, tokens o claves. random es determinista si se conoce la semilla, y un atacante podría predecir los valores. La documentación oficial de Python es explícita: “random shouldn’t be used for security purposes, use secrets instead”.

5.4. `argparse`: interfaces de línea de comandos

argparse permite definir argumentos posicionales y opcionales, generar ayuda automática y validar tipos.

import argparse
 
parser = argparse.ArgumentParser(description="Saluda a una persona.")
parser.add_argument("nombre", help="Nombre de la persona")
parser.add_argument("--veces", type=int, default=1, help="Número de saludos")
args = parser.parse_args()
 
for _ in range(args.veces):
    print(f"Hola, {args.nombre}")
[PYTHON] argparse es el módulo recomendado por la documentación oficial para interfaces de línea de comandos en la biblioteca estándar. Para interfaces más complejas, click o typer son alternativas populares de terceros.

5.5. `os.environ`: variables de entorno

Las variables de entorno son pares clave-valor que el sistema operativo pasa a los procesos. Se usan para configuración (rutas, credenciales, modos de ejecución) sin modificar el código. os.environ es un diccionario que las representa.

import os
 
# Leer una variable obligatoria (lanza KeyError si no existe)
modo = os.environ["MODO"]
 
# Leer una variable opcional con valor por defecto
debug = os.getenv("DEBUG", "false").lower() == "true"
[BUENA PRÁCTICA] No hardcodees credenciales en el código. Usa variables de entorno o archivos .env (con python-dotenv) para configuración sensible. Y añade .env al .gitignore (Módulo 19).

5.6. `pathlib`: archivos y directorios (repaso)

pathlib (Módulo 13) es la forma moderna y portable de manipular rutas. Ofrece operaciones como exists(), is_file(), mkdir(), iterdir(), read_text() y write_text().

from pathlib import Path
 
ruta = Path.home() / "datos" / "registro.txt"
ruta.parent.mkdir(parents=True, exist_ok=True)
ruta.write_text("Hola\n", encoding="utf-8")
[PYTHON] En Python 3.15, PurePath.is_reserved() se elimina (deprecado desde 3.13). Usa os.path.isreserved() si necesitas comprobar nombres reservados en Windows.

5.7. `re`: expresiones regulares

Las expresiones regulares son patrones para buscar, extraer y sustituir texto. El módulo re ofrece funciones como search, findall, sub y compile.

import re
 
texto = "Contacto: ana@example.com, luis@example.org"
correos = re.findall(r"[\w.+-]+@[\w-]+\.[\w.]+", texto)
print(correos)  # ['ana@example.com', 'luis@example.org']
 
# Sustituir
anonimizado = re.sub(r"[\w.+-]+@[\w-]+\.[\w.]+", "[email]", texto)
[NOVEDAD 3.15] re.match() está soft-deprecado en Python 3.15. Se ha añadido re.prefixmatch() como nombre más claro, porque match() ancla al principio de la cadena pero no al final, lo que confunde a muchos principiantes. En la mayoría de los casos, querrás re.search() (busca en cualquier posición) o re.fullmatch() (coincidencia completa).
[BUENA PRÁCTICA] Usa raw strings (r"...") para los patrones. Sin r, las barras invertidas se interpretan como secuencias de escape de Python, lo que produce errores difíciles de diagnosticar.

5.8. `urllib.request`: HTTP y APIs

urllib.request abre URLs y permite hacer peticiones HTTP básicas. Para APIs JSON, el flujo típico es: abrir la URL, leer la respuesta y parsearla con json.

import json
import urllib.request
 
with urllib.request.urlopen("https://api.example.com/datos", timeout=10) as respuesta:
    datos = json.load(respuesta)
print(datos["resultado"])
[PYTHON] urllib.request es funcional pero de bajo nivel. Para un cliente HTTP más cómodo, la comunidad recomienda la biblioteca de terceros requests, que simplifica el manejo de sesiones, JSON y errores. La documentación oficial de urllib.request la menciona como alternativa recomendada.
[SEGURIDAD] Nunca desactives la verificación de certificados TLS (ssl). Si una petición falla por un error de certificado, no es un problema que debas “saltarte”: indica que la conexión no es segura.

5.9. `sqlite3`: bases de datos ligeras

SQLite es una base de datos relacional en un solo archivo, sin servidor. El módulo sqlite3 implementa la especificación DB-API 2.0 (PEP 249).

import sqlite3
 
con = sqlite3.connect("tutorial.db")
cur = con.cursor()
cur.execute("CREATE TABLE IF NOT EXISTS peliculas (titulo TEXT, anio INTEGER)")
cur.execute("INSERT INTO peliculas VALUES (?, ?)", ("Monty Python", 1975))
con.commit()
 
for fila in cur.execute("SELECT titulo, anio FROM peliculas"):
    print(fila)
con.close()
[PYTHON] Usa siempre parámetros (?) en lugar de concatenar cadenas para evitar inyección SQL. cur.execute("SELECT * FROM t WHERE id = ?", (id,)) es seguro; cur.execute(f"SELECT * FROM t WHERE id = {id}") es vulnerable.
[NOVEDAD 3.15] En Python 3.15, los parámetros de sqlite3.connect() y del constructor Connection pasan a ser solo por palabra clave (keyword-only), y algunas APIs de Connection pasan a ser solo posicionales (positional-only). Si tienes código antiguo que pasa argumentos por posición, revisa la documentación al migrar.

5.10. Seguridad básica

La biblioteca estándar incluye módulos con consideraciones de seguridad específicas. Las más importantes para el nivel de este curso:

- random no es seguro para secretos. Usa secrets. - pickle y shelve no son seguros con datos no confiables. Pueden ejecutar código arbitrario al deserializar. - eval() y exec() ejecutan código arbitrario. Evítalos con datos de entrada. - No desactives la verificación TLS. - Usa el modo aislado (-I) o -P si ejecutas scripts en entornos no confiables, para evitar que el directorio actual se añada a sys.path.

[BUENA PRÁCTICA] La seguridad no es una característica que se añade al final: es una propiedad del diseño. Valida las entradas, usa parámetros en SQL, no confíes en datos externos y mantén las dependencias actualizadas.

6. Ejemplo completo comentado: descargar, procesar y guardar datos

import json
import sqlite3
import statistics
import urllib.request
from pathlib import Path
 
def descargar_datos(url):
    """Descarga datos JSON de una URL y devuelve una lista."""
    with urllib.request.urlopen(url, timeout=10) as respuesta:
        return json.load(respuesta)
 
def guardar_en_sqlite(datos, ruta_db):
    """Guarda una lista de diccionarios en una tabla SQLite."""
    con = sqlite3.connect(ruta_db)
    cur = con.cursor()
    cur.execute("CREATE TABLE IF NOT EXISTS registros (valor REAL)")
    cur.executemany("INSERT INTO registros VALUES (?)", [(d["valor"],) for d in datos])
    con.commit()
    con.close()
 
def calcular_estadisticas(valores):
    """Devuelve media, mediana y desviación típica."""
    return {
        "media": statistics.mean(valores),
        "mediana": statistics.median(valores),
        "stdev": statistics.stdev(valores) if len(valores) > 1 else 0,
    }
 
# Uso
# datos = descargar_datos("https://api.example.com/datos")
# valores = [d["valor"] for d in datos]
# print(calcular_estadisticas(valores))
# guardar_en_sqlite(datos, Path("datos.db"))

Seguimiento: El ejemplo combina varios módulos: urllib.request para la red, json para parsear, statistics para el análisis y sqlite3 para la persistencia. Cada función tiene una responsabilidad clara (Módulo 9 y 16). Los errores de red o de base de datos deben manejarse con try/except (Módulo 11) en código de producción.


7. Errores habituales

ErrorCausaCómo evitarlo
KeyError en os.environ["VAR"]La variable no existe.Usa os.getenv("VAR", default) si es opcional.
re.match() no encuentra lo esperadomatch solo busca al principio.Usa re.search() o re.fullmatch(); en 3.15, re.prefixmatch().
Inyección SQLConcatenar cadenas en execute.Usa parámetros ?.
Contraseñas predeciblesUsar random.Usa secrets.
datetime naive en zonas horariasNo se especifica tzinfo.Usa timezone.utc o zoneinfo.ZoneInfo.
NaN en statistics.medianLos NaN rompen el orden.Filtra los NaN antes.
urllib falla por certificadoTLS no verificado o cadena incompleta.No desactives la verificación; revisa la configuración de certificados.

8. Particularidades de Python frente a otros lenguajes

- Biblioteca estándar “batteries included”: Python incluye módulos para HTTP, SQLite, JSON, CSV, expresiones regulares, correo, compresión, etc. En C o Java, muchas de estas funcionalidades requieren bibliotecas externas. - argparse en la biblioteca estándar: Java o C no tienen un equivalente directo; suelen usar bibliotecas de terceros. - secrets frente a random: la separación explícita entre aleatoriedad estadística y criptográfica es una práctica de seguridad que Python hace visible en la biblioteca estándar. - sqlite3 integrado: SQLite es una biblioteca C externa, pero Python la incluye como módulo estándar, lo que facilita prototipos y aplicaciones pequeñas. - re.prefixmatch() (3.15): la evolución del lenguaje para corregir nombres confusos (match) muestra la importancia de la legibilidad en la API estándar.


9. Buenas prácticas

- Consulta la documentación oficial antes de escribir una función desde cero. La biblioteca estándar suele tener una solución probada. - Usa pathlib para rutas portables. - Usa secrets para cualquier valor que deba ser impredecible. - Usa parámetros en SQL para evitar inyección. - Maneja los errores de red y de base de datos con try/except específicos. - No hardcodees configuración sensible: usa variables de entorno. - Para HTTP de alto nivel, considera requests en lugar de urllib.request.


10. Windows y Linux

- datetime, statistics, math, re, sqlite3, urllib funcionan igual en ambos sistemas. - os.environ es portable, pero las variables de entorno disponibles dependen del sistema. Documenta las que uses. - pathlib unifica las rutas; evita concatenar con \ o / manualmente. - sqlite3 crea el archivo de base de datos en la ruta indicada; usa pathlib para construirla de forma portable. - urllib.request usa los certificados del sistema; en algunos entornos Linux minimalistas puede ser necesario instalar ca-certificates.


11. Ejercicios guiados

Ejercicio guiado 1: Calcular la edad.

Pide al usuario su fecha de nacimiento en formato DD/MM/AAAA y calcula su edad con datetime. Maneja el caso de formato inválido con try/except ValueError.

Ejercicio guiado 2: Estadísticas de una lista.

Pide una lista de números separados por comas, conviértelos a float y muestra la media, la mediana y la desviación típica con statistics.

Ejercicio guiado 3: Token seguro.

Genera un token de restablecimiento de contraseña con secrets.token_urlsafe(32). Muestra el token y explica por qué no usarías random para esto.


12. Ejercicios autónomos

1. Expresiones regulares: Extrae todas las direcciones de correo de un texto y sustitúyelas por [oculto]. 2. argparse: Escribe un script que reciba una ruta de archivo y una palabra, y cuente cuántas veces aparece la palabra en el archivo. Usa argparse con ayuda automática. 3. SQLite: Crea una base de datos agenda.db con una tabla contactos(nombre, telefono). Inserta tres contactos y consulta todos los que empiecen por “A”. 4. HTTP: Descarga un JSON de una API pública (por ejemplo, https://api.github.com/users/python) y muestra el nombre y el número de repositorios públicos. 5. Reto opcional: Investiga math.integer en Python 3.15 y escribe un script que calcule el máximo común divisor y el mínimo común múltiplo de una lista de números usando este submódulo.


13. Soluciones razonadas

Solución al ejercicio guiado 1:

from datetime import datetime
 
fecha_texto = input("Fecha de nacimiento (DD/MM/AAAA): ")
try:
    nacimiento = datetime.strptime(fecha_texto, "%d/%m/%Y").date()
    hoy = datetime.now().date()
    edad = hoy.year - nacimiento.year - ((hoy.month, hoy.day) < (nacimiento.month, nacimiento.day))
    print(f"Tienes {edad} años.")
except ValueError:
    print("Formato de fecha inválido.")

strptime parsea la fecha; el cálculo de edad ajusta el año si aún no ha llegado el cumpleaños.

Solución al ejercicio 2:

import statistics
 
entrada = input("Números separados por comas: ")
numeros = [float(n) for n in entrada.split(",")]
print(statistics.mean(numeros))
print(statistics.median(numeros))
print(statistics.stdev(numeros))

Solución al ejercicio 3: secrets.token_urlsafe(32) genera un token seguro. No se usa random porque su secuencia es predecible si se conoce la semilla, lo que comprometería la seguridad del restablecimiento.

Solución al ejercicio 5 (orientativa):

from math import integer
 
numeros = [12, 18, 24]
print(integer.gcd(*numeros))
print(integer.lcm(*numeros))

math.integer agrupa las funciones enteras en 3.15.


Resumen

  • La biblioteca estándar cubre fechas, estadísticas, aleatoriedad, CLI, entorno, archivos, texto, red y bases de datos.
  • datetime maneja fechas y horas; usa objetos aware para zonas horarias.
  • math y statistics ofrecen funciones matemáticas y estadísticas; math.integer es nuevo en 3.15.
  • random es para simulaciones; secrets para seguridad.
  • argparse crea interfaces de línea de comandos con ayuda automática.
  • os.environ y pathlib gestionan configuración y rutas.
  • re usa expresiones regulares; re.prefixmatch() sustituye a re.match() en 3.15.
  • urllib.request hace peticiones HTTP; requests es la alternativa de alto nivel.
  • sqlite3 integra SQLite; usa parámetros para evitar inyección SQL.
  • La seguridad básica incluye no usar random para secretos, no confiar en pickle con datos externos y no desactivar TLS.
informatica/programacion/cursos/programacion_desde_cero_con_python/biblioteca_estandar_y_aplicaciones_utiles.txt · Última modificación: por tempwin