La biblioteca estándar de Python
En esta lección
- Cómo orientarte
- math: algo más que raíces
- random: azar que puedes repetir
- statistics: resumir datos
- pathlib y os: archivos y carpetas
- sys: el intérprete y la línea de comandos
- collections: estructuras de datos extra
- itertools: combinar y agrupar
- time: medir y esperar
- shutil: copiar, mover y borrar en bloque
- Errores frecuentes
- Resumen
Python trae instalados de serie cientos de módulos que resuelven tareas muy comunes: cálculos, números aleatorios, estadística, rutas y carpetas, conteos, combinaciones o medir tiempos. A ese conjunto se le llama biblioteca estándar. En la lección de módulos viste cómo importarlos y un vistazo rápido a cada uno; aquí vas a ir un paso más allá, con un ejemplo útil de cada módulo para que sepas cuándo echar mano de él antes de reinventar la rueda.
Cómo orientarte
Antes de escribir una función, pregúntate si ya existe. La documentación oficial (docs.python.org, con versión en español) tiene un índice de toda la biblioteca. Desde la consola interactiva también puedes explorar:
import statistics
print([n for n in dir(statistics) if n.startswith("med")])
# ['median', 'median_grouped', 'median_high', 'median_low']
dir() lista lo que contiene un módulo (aquí, solo los nombres que empiezan por “med”) y help(statistics.median) muestra la ayuda de una función concreta.
math: algo más que raíces
Además de sqrt, ceil y floor, math tiene funciones que resuelven problemas muy concretos.
import math
# ¿Cuántas cajas de 12 huevos necesito para 50 huevos?
print(math.ceil(50 / 12)) # 5
# Comparar decimales sin sorpresas
print(0.1 + 0.2 == 0.3) # False
print(math.isclose(0.1 + 0.2, 0.3)) # True
# Distancia en línea recta entre dos puntos (x, y)
print(math.dist((0, 0), (3, 4))) # 5.0
# Producto de todos los elementos y máximo común divisor
print(math.prod([2, 3, 4])) # 24
print(math.gcd(48, 36)) # 12
math.isclosees la forma correcta de comparar números con decimales. Por cómo se guardan en memoria,0.1 + 0.2vale0.30000000000000004, y==falla.math.gcd(máximo común divisor) sirve, por ejemplo, para simplificar fracciones o repartir en grupos iguales.math.infrepresenta el infinito; es útil como valor inicial al buscar un mínimo.
random: azar que puedes repetir
random genera números pseudoaleatorios: parecen al azar, pero salen de una fórmula que parte de un valor inicial llamado semilla. Si fijas la semilla con random.seed, obtienes siempre la misma secuencia. Es muy útil para hacer pruebas o para que un compañero pueda reproducir tu resultado.
import random
random.seed(42)
print(random.randint(1, 6)) # 6
print(random.choice(["Ana", "Luis", "Eva"])) # Ana
print(round(random.uniform(10, 20), 2)) # 10.25
Ejecútalo varias veces y verás siempre lo mismo. Quita la línea de seed y cada ejecución dará algo distinto.
Un sorteo de grupos reproducible
alumnos = ["Ana", "Luis", "Eva", "Marcos", "Sara", "Iker"]
random.seed(2026)
mezclados = alumnos[:] # copia, para no desordenar la original
random.shuffle(mezclados)
grupos = [mezclados[i:i + 2] for i in range(0, len(mezclados), 2)]
print(grupos)
# [['Sara', 'Luis'], ['Marcos', 'Iker'], ['Eva', 'Ana']]
Elegir con pesos: choices
choice elige un elemento; choices elige varios con reemplazo (pueden repetirse) y admite pesos:
random.seed(8)
premios = ["nada", "pegatina", "camiseta"]
print(random.choices(premios, weights=[70, 25, 5], k=6))
# ['nada', 'camiseta', 'nada', 'pegatina', 'nada', 'nada']
Cada tirada tiene un 70 % de “nada”, un 25 % de “pegatina” y un 5 % de “camiseta”. Si no quieres repeticiones, usa random.sample(lista, k).
Cuidado:
randomno es seguro para contraseñas, tokens o códigos de verificación, porque su secuencia se puede predecir. Para eso usa el módulosecrets:secrets.token_hex(16)osecrets.choice(caracteres).
statistics: resumir datos
Imagina que registras los minutos que tardas en una ruta de running cada día:
import statistics as st
tiempos = [31, 29, 35, 30, 29, 42, 28]
print(st.mean(tiempos)) # 32 (media)
print(st.median(tiempos)) # 30 (mediana)
print(st.mode(tiempos)) # 29 (el más repetido)
print(round(st.stdev(tiempos), 2)) # 4.97 (desviación típica)
print(st.quantiles(tiempos, n=4)) # [29.0, 30.0, 35.0]
La media se ve afectada por el día malo de 42 minutos; la mediana (el valor central una vez ordenados) no. Por eso en datos con valores extremos, como sueldos o precios de pisos, se suele dar la mediana. La desviación típica mide cuánto se alejan los datos de la media: cuanto más pequeña, más regular eres. quantiles(n=4) devuelve los tres cuartiles, los puntos que dividen los datos en cuatro partes.
pathlib y os: archivos y carpetas
pathlib representa rutas como objetos y es la opción moderna; ya la viste en ficheros. Vamos a usarla para algo práctico: preparar una carpeta con archivos de prueba y listarlos.
from pathlib import Path
carpeta = Path("descargas")
carpeta.mkdir(exist_ok=True)
for nombre in ["foto1.jpg", "apuntes.pdf", "foto2.jpg", "notas.txt"]:
(carpeta / nombre).write_text("contenido de prueba", encoding="utf-8")
for archivo in sorted(carpeta.iterdir()):
if archivo.is_file():
print(archivo.name, archivo.suffix, archivo.stat().st_size, "bytes")
# apuntes.pdf .pdf 19 bytes
# foto1.jpg .jpg 19 bytes
# foto2.jpg .jpg 19 bytes
# notas.txt .txt 19 bytes
print([p.name for p in sorted(carpeta.glob("*.jpg"))]) # ['foto1.jpg', 'foto2.jpg']
iterdir()recorre lo que hay en la carpeta (archivos y subcarpetas);is_file()se queda solo con los archivos.glob("*.jpg")filtra por patrón;rglobbusca también en subcarpetas.stat().st_sizeda el tamaño en bytes.Path.cwd()devuelve la carpeta actual yPath.home()la carpeta personal del usuario.
El módulo os sigue siendo útil para hablar con el sistema operativo. Lo que más usarás son las variables de entorno, valores de configuración que se definen fuera del programa (claves de API, modo de depuración):
import os
modo = os.environ.get("MODO", "desarrollo") # valor por defecto si no existe
print(modo) # desarrollo
Consejo: para rutas, prefiere
pathlibaos.path. Verásos.path.join,os.listdiryos.path.existsen código antiguo; hacen lo mismo que/,iterdir()yexists().
sys: el intérprete y la línea de comandos
sys.argv es la lista de argumentos con que se lanzó el programa desde la terminal. El primero es siempre el nombre del script. sys.exit termina el programa; por convención, el código 0 significa “todo bien” y cualquier otro número, error.
# saludo.py
import sys
if len(sys.argv) < 2:
print("Uso: python saludo.py NOMBRE")
sys.exit(1)
nombre = sys.argv[1]
print(f"Hola, {nombre}")
python saludo.py Lucía # Hola, Lucía
python saludo.py # Uso: python saludo.py NOMBRE
Este bloque no tiene sentido ejecutarlo en la web, porque aquí no hay terminal desde la que pasar argumentos. Otros datos útiles de sys:
import sys
print(sys.version_info >= (3, 10)) # True (si tu Python es 3.10 o superior)
sys.version_info sirve para comprobar la versión, y sys.platform dice el sistema ("win32", "linux", "darwin" en macOS). Para programas con muchas opciones (--ayuda, -v), el módulo argparse genera la ayuda y valida los argumentos por ti.
collections: estructuras de datos extra
Counter: contar cosas
from collections import Counter
resena = "muy buena comida y muy buen servicio la comida llegó caliente"
palabras = Counter(resena.split())
print(palabras.most_common(2)) # [('muy', 2), ('comida', 2)]
palabras.update(["comida", "postre"]) # suma más apariciones
print(palabras["comida"], palabras["pizza"]) # 3 0
Un Counter es un diccionario especial: si preguntas por algo que no está, devuelve 0 en lugar de lanzar KeyError.
defaultdict: diccionarios con valor inicial
Con defaultdict(int), cada clave nueva empieza valiendo 0; con defaultdict(list), una lista vacía. Así acumulas sin comprobar si la clave existe:
from collections import defaultdict
gastos = [("comida", 12.5), ("ocio", 20), ("comida", 8), ("transporte", 3.4)]
por_categoria = defaultdict(float)
for categoria, importe in gastos:
por_categoria[categoria] += importe
print(dict(por_categoria)) # {'comida': 20.5, 'ocio': 20.0, 'transporte': 3.4}
namedtuple: tuplas con nombre
Una tupla con nombre se comporta como una tupla normal, pero sus elementos también se leen por nombre. Es ideal para datos pequeños que no cambian:
from collections import namedtuple
Punto = namedtuple("Punto", ["lat", "lon"])
cima = Punto(43.17, -4.85)
print(cima.lat, cima[1]) # 43.17 -4.85
print(cima._asdict()) # {'lat': 43.17, 'lon': -4.85}
Si además necesitas métodos o valores por defecto, una dataclass suele ser mejor opción.
deque: cola por los dos extremos
Una deque (double-ended queue, se pronuncia “dek”) permite añadir y quitar por ambos lados de forma rápida. Con maxlen se queda solo con los últimos elementos, perfecto para un historial:
from collections import deque
historial = deque(maxlen=3)
for pagina in ["inicio", "cursos", "python", "retos"]:
historial.append(pagina)
print(historial) # deque(['cursos', 'python', 'retos'], maxlen=3)
cola = deque(["Ana", "Luis"])
cola.append("Eva") # llega alguien al final
print(cola.popleft()) # Ana (atiende al primero)
En una lista, pop(0) tiene que mover todos los elementos; en una deque, popleft() es instantáneo aunque haya millones.
itertools: combinar y agrupar
product: todas las combinaciones de varias listas
import itertools
tallas = ["S", "M"]
colores = ["negro", "blanco"]
for talla, color in itertools.product(tallas, colores):
print(f"Camiseta {talla} {color}")
# Camiseta S negro
# Camiseta S blanco
# Camiseta M negro
# Camiseta M blanco
Equivale a dos for anidados, pero se lee mejor y funciona con cualquier número de listas.
combinations: grupos sin orden
¿Qué partidos hay en una liguilla de cuatro equipos si todos juegan contra todos una vez?
equipos = ["Racing", "Gimnástica", "Laredo", "Escobedo"]
partidos = list(itertools.combinations(equipos, 2))
print(len(partidos)) # 6
print(partidos[0]) # ('Racing', 'Gimnástica')
Si el orden importa (ida y vuelta), usa permutations, que da 12.
groupby: agrupar elementos consecutivos
groupby agrupa elementos seguidos que comparten una clave. Por eso casi siempre hay que ordenar antes por esa misma clave:
ventas = [("enero", 120), ("febrero", 80), ("enero", 45), ("febrero", 30), ("marzo", 60)]
ventas.sort(key=lambda v: v[0])
for mes, grupo in itertools.groupby(ventas, key=lambda v: v[0]):
print(mes, sum(importe for _, importe in grupo))
# enero 165
# febrero 110
# marzo 60
Sin el sort, “enero” aparecería dos veces. Para agrupar sin ordenar, el defaultdict de antes es más sencillo.
time: medir y esperar
time.perf_counter() devuelve un contador de alta precisión. Restando dos lecturas sabes cuánto ha tardado un trozo de código:
import time
inicio = time.perf_counter()
total = sum(range(1_000_000))
duracion = time.perf_counter() - inicio
print(f"Suma: {total}, tiempo: {duracion:.4f} s")
# Suma: 499999500000, tiempo: 0.0123 s (el tiempo varía en cada equipo)
time.sleep(segundos) pausa el programa, útil para no saturar un servidor con peticiones seguidas. time.time() da los segundos desde 1970 (la llamada marca de tiempo Unix). Para trabajar con fechas legibles usa datetime.
shutil: copiar, mover y borrar en bloque
pathlib crea, lee y borra archivos sueltos; shutil hace operaciones de más alto nivel. Con la carpeta descargas de antes, vamos a ordenar los archivos en subcarpetas según su extensión:
import shutil
for archivo in list(carpeta.iterdir()):
if archivo.is_file():
destino = carpeta / archivo.suffix[1:] # "jpg", "pdf", "txt"
destino.mkdir(exist_ok=True)
shutil.move(archivo, destino / archivo.name)
print(sorted(str(p.relative_to(carpeta)) for p in carpeta.rglob("*.*")))
# ['jpg/foto1.jpg', 'jpg/foto2.jpg', 'pdf/apuntes.pdf', 'txt/notas.txt']
shutil.copytree(carpeta, "copia_descargas", dirs_exist_ok=True) # copia la carpeta entera
shutil.rmtree("copia_descargas") # y la borra con todo su contenido
| Función | Qué hace |
|---|---|
shutil.copy(origen, destino) | Copia un archivo |
shutil.copytree(origen, destino) | Copia una carpeta con todo su contenido |
shutil.move(origen, destino) | Mueve o renombra |
shutil.rmtree(carpeta) | Borra una carpeta y todo lo que tiene |
shutil.make_archive("copia", "zip", carpeta) | Crea un ZIP de una carpeta |
Cuidado:
shutil.rmtreeborra sin pasar por la papelera y sin preguntar. Comprueba bien la ruta antes de ejecutarlo, sobre todo si la construyes con variables.
Errores frecuentes
- Llamar a tu archivo como un módulo (
random.py,statistics.py): tu archivo tapa al original y aparecen errores comomodule 'random' has no attribute 'seed'. - Comparar decimales con
==: usamath.isclose. - Usar
randompara contraseñas: usasecrets. - Olvidar ordenar antes de
groupby: el mismo grupo sale varias veces. - Confundir
choicesysample:choicespuede repetir elementos;sample, no. - Leer
sys.argv[1]sin comprobar la longitud: si no pasan argumentos,IndexError. - Escribir rutas con
"\\"o"/"a mano: usaPathy el operador/.
Resumen
| Módulo | Para qué lo usarás |
|---|---|
math | ceil, isclose, dist, prod, gcd, inf |
random | seed, randint, choice, choices con pesos, shuffle, sample |
secrets | Valores aleatorios seguros (tokens, contraseñas) |
statistics | mean, median, mode, stdev, quantiles |
pathlib | Rutas, iterdir, glob, mkdir, tamaño de archivos |
os | Variables de entorno con os.environ.get |
sys | argv, exit, version_info, platform |
collections | Counter, defaultdict, namedtuple, deque |
itertools | product, combinations, permutations, groupby |
time | perf_counter para medir, sleep para esperar |
shutil | Copiar, mover y borrar carpetas enteras |
La biblioteca estándar es enorme y no hace falta memorizarla: basta con saber que existe y buscar cuando lo necesites. En la siguiente lección aprenderás a buscar y validar patrones de texto con expresiones regulares.
Pon a prueba lo que has aprendido
¿Te ha quedado claro? Márcala y verás tu progreso en el explorador.