🐍 Curso Python · Nivel N3 Intermedio

Bloque 5: Biblioteca estándar

Python trae «pilas incluidas»: decenas de módulos listos para usar sin instalar nada. En este bloque recorres los más rentables: sistema y rutas (os, pathlib, sys), tiempo y fechas, math/random/statistics, collections (Contadores y amigos), JSON y CSV, expresiones regulares y utilidades como itertools o argparse. Remata con entornos virtuales y un analizador de logs.

⏱ ≈ 19 horas 📚 5 lecciones ✍️ 15 ejercicios guiados 📝 Examen del bloque + analizador de logs
Lección 1 · Teoría

os, pathlib y sys

1.1 · pathlib: rutas modernas

pathlib trata las rutas como objetos en vez de cadenas. Es el módulo moderno para trabajar con ficheros y carpetas:

rutas con pathlib
from pathlib import Path

p = Path("datos") / "2026" / "notas.txt"
print(p.exists())      # ¿hay algo ahí?
print(p.suffix)       # .txt
print(p.name)        # notas.txt

p.parent.mkdir(parents=True, exist_ok=True)  # crea carpetas si falta
p.write_text("hola")
print(p.read_text())

1.2 · os y sys: lo clásico de sistema

os.getcwd() devuelve la carpeta actual, os.listdir() el contenido, y os.environ las variables de entorno. sys.argv captura los argumentos que pasas al ejecutar un script:

sistema y argumentos
import sys
import os

print(os.name)               # 'posix' en Linux/Mac, 'nt' en Windows
print(sys.version)          # versión de Python
print(sys.argv)             # $ python app.py a b → ['app.py', 'a', 'b']
💡 Prefiere pathlib para rutas (más legible y multiplataforma) y deja os.path solo para compatibilidad con código antiguo.
Lección 2 · Teoría

Tiempo, math, random y statistics

2.1 · datetime

fechas y horas
import datetime

hoy = datetime.date.today()
print(hoy)                        # 2026-09-01
print(hoy.year, hoy.strftime("%d/%m/%Y"))  # 2026 01/09/2026

fecha = datetime.datetime(2026, 12, 31, 23, 59)
diferencia = fecha - datetime.datetime.now()
print(diferencia.days)             # días que quedan

2.2 · math, random y statistics

mates, aleatoriedad y estadística
import math
import random
import statistics

print(math.pi, math.sqrt(16), math.floor(2.9))
print(random.randint(1, 6), random.choice(["rojo", "verde", "azul"]))

notas = [7, 8, 9, 6.5, 10]
print(statistics.mean(notas))    # media
print(statistics.median(notas))  # mediana
⚠️ math también trae ceil (redondeo arriba), trunc, gcd, factorial, log y la raíz pow(x, y). Consulta dir(math) cuando dudes: te lo cuenta todo.
Lección 3 · Teoría

collections: Counter y amigos

3.1 · Counter: contar elementos

Counter cuenta automáticamente los elementos de una lista o un texto. Es de lo más usado de la biblioteca estándar:

contadores de letras
from collections import Counter

palabras = "gato perro gato pajaro gato".split()
conteo = Counter(palabras)

print(conteo)              # Counter({'gato': 3, 'perro': 1, 'pajaro': 1})
print(conteo["gato"])     # 3
print(conteo.most_common(2))  # top 2

3.2 · defaultdict, namedtuple y deque

defaultdict y namedtuple
from collections import defaultdict, namedtuple

# defaultdict: si falta la clave, crea el valor por defecto
agrupado = defaultdict(list)
agrupado["frutas"].append("manzana")   # no lanza KeyError

# namedtuple: tuplas con nombre (ligeras y legibles)
Punto = namedtuple("Punto", "x y")
p = Punto(x=1, y=2)
print(p.x, p.y)   # 1 2

deque es una lista optimizada para añadir/quitar por ambos extremos (appendleft, popleft). Perfecta para colas y buffer deslizantes.

Lección 4 · Teoría

JSON, CSV y expresiones regulares

4.1 · re: expresiones regulares

Las regex buscan patrones en texto. El módulo re da search (¿existe?), findall (todas la coincidencias) y sub (reemplazar):

buscar patrones
import re

texto = "Contacta: ana@correo.es o 600 12 34 56 (teléfono)"

# encontrar todos los emails
emails = re.findall(r"[\w.]+@[\w.]+", texto)
print(emails)   # ['ana@correo.es']

# ¿contiene un teléfono?
if re.search(r"\d{3}\s?\d{2}\s?\d{2}\s?\d{2}", texto):
    print("tiene teléfono")
💡 Los patrones se escriben con prefijo r (raw string) para que la barra inversa \d no se escape dos veces. Clases de caracteres: \d (dígito), \w (letra/número/_), \s (espacio), + (1 o más), * (0 o más), [] (listado), | (o).

4.2 · CSV: tablas en texto

leer y escribir CSV
import csv

# escribir
with open("ventas.csv", "w", newline="", encoding="utf-8") as f:
    writer = csv.DictWriter(f, fieldnames=["mes", "importe"])
    writer.writeheader()
    writer.writerow({"mes": "enero", "importe": 120})

# leer
with open("ventas.csv", encoding="utf-8") as f:
    for fila in csv.DictReader(f):
        print(fila)
⚠️ En open(..., "w") para CSV usa newline="": evita saltos de línea extra en Windows. Parece raro pero es obligatorio.

4.3 · JSON en profundidad

cargar y volcar
import json

cadena = '{"nombre": "Ana", "edad": 25}'
datos = json.loads(cadena)           # str → dict
print(datos["nombre"])

salida = json.dumps(datos, ensure_ascii=False)   # dict → str
print(salida)
Lección 5 · Teoría

itertools, functools y entornos virtuales

5.1 · itertools: iteradores potentes

product (producto cartesiano), combinations (combinaciones) y cycle/islice ahorran bucles manuales:

combinaciones y producto
from itertools import combinations, product

print(list(combinations([1, 2, 3], 2)))   # pares
print(list(product("AB", "12")))      # todas las parejas

5.2 · functools: map/reduce y caché

reduce y lru_cache
from functools import reduce, lru_cache

# reduce: acumula un resultado
total = reduce(lambda a, b: a + b, [1, 2, 3, 4])
print(total)   # 10

@lru_cache(maxsize=None)
def fib(n):
    if n < 2:
        return n
    return fib(n - 1) + fib(n - 2)

5.3 · Entornos virtuales con venv

Un entorno virtual aísla los paquetes de cada proyecto. Es la típica operación de terminal que hace todo profesional:

venv + pip + requirements
$ python -m venv .venv          # crea el entorno
$ source .venv/bin/activate     # lo activa (PowerShell: .venv\Scripts\activate)
$ pip install requests          # instala solo en este proyecto
$ pip freeze > requirements.txt # guarda la lista exacta
$ deactivate                   # sale del entorno
💡 Con requirements.txt cualquier otra persona reproduce tu entorno con un solo comando: pip install -r requirements.txt. Luego importas esas librerías como si fueran del estándar.
🎉 La biblioteca estándar te da un 80 % de los problemas resueltos. Leer configs, fechas, estadísticas, ficheros CSV/JSON y scripts de consola ya no va a requerir «código inventado»: lo resuelves con módulos oficiales.
Manos a la obra

✍️ Los 15 ejercicios del bloque

Crea la carpeta python-b5/ y un archivo .py por ejercicio. Muchos son «un módulo del estándar + tu lógica»: impórtalo y deja que haga el trabajo pesado.

Sección A · Sistema, fechas y números

1 Hola pathlib

Crea con Path("datos") / "saludo.txt", escribe "¡Hola, Python!" con write_text() y luego lee y muestra el contenido con read_text().

Ver solución
from pathlib import Path

p = Path("datos") / "saludo.txt"
p.write_text("¡Hola, Python!", encoding="utf-8")
print(p.read_text(encoding="utf-8"))

2 Listar la carpeta actual

Con os.listdir(".") lista el contenido de la carpeta actual y muéstralo uno por línea.

Ver solución
import os

for item in os.listdir("."):
    print(item)

3 Argumentos del script

Usa sys.argv y muestra «Recibidos n argumentos» (contando desde 0) e imprime cada argumento. Ejecútalo con: python ejercicio3.py uno dos.

Ver solución
import sys

print(f"Recibidos {len(sys.argv)} argumentos")
for arg in sys.argv:
    print(arg)

4 Fecha formateada

Con datetime.date.today() muestra la fecha de hoy en formato español «día/mes/año» y el día de la semana con strftime.

Ver solución
import datetime

hoy = datetime.date.today()
print(hoy.strftime("%d/%m/%Y"))
print(hoy.strftime("%A"))

5 Área con math

Con math.pi pide el radio con input() y muestra el área del círculo (pi * r ** 2) redondeada a 2 decimales.

Ver solución
import math

radio = float(input("Radio: "))
area = math.pi * radio ** 2
print(f"Área: {area:.2f}")

6 Dado virtual

Lanza un random.randint(1, 6) 100 veces y muestra cuántas veces salió cada cara usando Counter.

Ver solución
import random
from collections import Counter

tiradas = [random.randint(1, 6) for _ in range(100)]
print(Counter(tiradas))

7 Notas con statistics

Toma notas = [7, 8, 9.5, 6, 10, 7.5] y muestra media, mediana y la moda (con statistics).

Ver solución
import statistics

notas = [7, 8, 9.5, 6, 10, 7.5]
print(statistics.mean(notas))
print(statistics.median(notas))
print(statistics.mode(notas))

Sección B · collections, CSV y JSON

8 Palabras más frecuentes

Dado el texto "el gato y el perro; el gato duerme", limpia los signos con re, crea un Counter y muestra las 2 palabras más frecuentes con most_common.

Ver solución
import re
from collections import Counter

texto = "el gato y el perro; el gato duerme"
limpio = re.sub(r"[;,.!?]", " ", texto).lower()
conteo = Counter(limpio.split())
print(conteo.most_common(2))

9 defaultdict de listas

Con defaultdict(list) agrupa por inicial: para una lista de nombres, cada letra inicial tendrá su lista de nombres. Muéstralo.

Ver solución
from collections import defaultdict

nombres = ["Ana", "Alberto", "Luis", "Lucía"]
grupos = defaultdict(list)
for nombre in nombres:
    grupos[nombre[0]].append(nombre)
print(dict(grupos))

10 Emails del texto

Extrae con re.findall todos los emails del texto "Escriba a a@b.es, c@d.com o llame al 900 000 000". Muéstralos.

Ver solución
import re

texto = "Escriba a a@b.es, c@d.com o llame al 900 000 000"
emails = re.findall(r"[\w.]+@[\w.]+", texto)
print(emails)

11 CSV con DictReader

Crea ventas.csv (cabeceras mes,importe) con 3 ventas usando csv.DictWriter y luego súmalas leyendo con csv.DictReader.

Ver solución
import csv

with open("ventas.csv", "w", newline="", encoding="utf-8") as f:
    w = csv.DictWriter(f, fieldnames=["mes", "importe"])
    w.writeheader()
    w.writerow({"mes": "ene", "importe": 100})
    w.writerow({"mes": "feb", "importe": 150})
    w.writerow({"mes": "mar", "importe": 200})

total = 0
with open("ventas.csv", encoding="utf-8") as f:
    for fila in csv.DictReader(f):
        total += float(fila["importe"])
print(total)   # 450.0

12 Config en JSON

Guarda {"usuario": "ana", "tema": "oscuro", "notificaciones": True} en config.json con indent 2, cárgalo después y muestra tema.

Ver solución
import json

config = {"usuario": "ana", "tema": "oscuro", "notificaciones": True}
with open("config.json", "w", encoding="utf-8") as f:
    json.dump(config, f, ensure_ascii=False, indent=2)

with open("config.json", encoding="utf-8") as f:
    carga = json.load(f)
print(carga["tema"])

13 Pares con itertools

Con itertools.combinations muestra todas las parejas posibles de ["Ana", "Luis", "Rita"] y luego con product el producto cartesiano de "AB" y "12".

Ver solución
from itertools import combinations, product

print(list(combinations(["Ana", "Luis", "Rita"], 2)))
print(list(product("AB", "12")))

14 reduce acumulado

Con functools.reduce sin importar sum, calcula el producto de [1, 2, 3, 4] (debe dar 24).

Ver solución
from functools import reduce

producto = reduce(lambda a, b: a * b, [1, 2, 3, 4])
print(producto)   # 24

15 🏆 Proyecto integrador: «analizador de logs»

Crea analizador.py: lee un fichero servidor.log (líneas con fecha, nivel y mensaje) y produce estadísticas. Requisitos:

  • Genera servidor.log con 10+ líneas tipo "2026-09-01 10:00:10 INFO Servicio iniciado" (varía INFO/ERROR/WARN).
  • Lee el fichero con Path y código utf-8.
  • Con re, extrae el nivel de cada línea.
  • Con Counter, cuenta cuántos INFO, ERROR y WARN hay y muéstralo ordenado con most_common.
  • Cuenta también en qué fecha hubo más errores (usa slicing de la fecha).
  • Guardar el resumen en resumen.json con json.dump.
  • Un try/except FileNotFoundError con mensaje amigable.
  • Todo documentado con una función y un docstring.
Ver una solución posible
import re
import json
from pathlib import Path
from collections import Counter

lineas_muestra = [
    "2026-09-01 10:00:10 INFO Servicio iniciado",
    "2026-09-01 10:02:30 WARN Memoria alta",
    "2026-09-01 10:05:10 ERROR No responde el API",
    "2026-09-02 09:10:10 INFO Backup completado",
    "2026-09-02 09:15:40 ERROR Timeout en BD",
    "2026-09-02 09:16:00 ERROR Conexión perdida",
    "2026-09-03 08:00:00 INFO Reinicio programado",
    "2026-09-03 08:01:20 WARN Cache desactualizada",
    "2026-09-03 08:05:50 ERROR Disco casi lleno",
    "2026-09-03 08:06:40 INFO Proceso finalizado",
]

Path("servidor.log").write_text("\n".join(lineas_muestra), encoding="utf-8")

def analizar(ruta):
    """Devuelve el recuento de niveles y los errores por fecha."""
    niveles = []
    errores_por_fecha = Counter()
    try:
        texto = Path(ruta).read_text(encoding="utf-8")
    except FileNotFoundError:
        print("No existe el fichero de logs")
        return Counter(), Counter()

    for linea in texto.splitlines():
        nivel = re.search(r"\b(INFO|WARN|ERROR)\b", linea)
        if nivel:
            niveles.append(nivel.group(1))
            if nivel.group(1) == "ERROR":
                errores_por_fecha[linea[:10]] += 1
    return Counter(niveles), errores_por_fecha

resumen, errores = analizar("servidor.log")
print(resumen.most_common())

with open("resumen.json", "w", encoding="utf-8") as f:
    json.dump({"niveles": dict(resumen), "errores_por_fecha": dict(errores)}, f,
              ensure_ascii=False, indent=2)
Evaluación del bloque

📝 Examen del Bloque 5

Dos partes: un test teórico autoevaluable (mínimo 70 %) y un reto práctico de autocorrección con laboratorio.

Parte A · Test teórico (aprueba con 11/15)

1 · ¿Qué módulo moderno se recomienda para trabajar con rutas?
2 · ¿Qué contiene sys.argv?
3 · ¿Qué haría hoy.strftime("%d/%m/%Y")?
4 · ¿Qué módulo da media, mediana y moda?
5 · ¿Qué te devuelve Counter(texto.split()).most_common(2)?
6 · ¿Qué evita KeyError con dicts anidando listas?
7 · ¿Qué significa el prefijo r antes de un patrón?
8 · ¿Cuál es el patrón para un dígito en regex?
9 · En open(..., "w") para CSV, ¿qué valor se pasa a newline?
10 · ¿Qué hace json.loads(cadena)?
11 · ¿Para qué sirve itertools.combinations?
12 · ¿Qué hace @lru_cache sobre una función?
13 · ¿Qué crea el comando python -m venv?
14 · ¿Qué guarda pip freeze > requirements.txt?
15 · ¿Qué hace os.listdir(".")?

Parte B · Reto «estadísticas del estándar»

Crea conteo_palabras.py: que cuente palabras frecuentes de un texto usando la biblioteca estándar. Valida tú mismo/a estos criterios. Mínimo para aprobar: 6 de 8 casillas.

Cumplidos: 0 / 8

🎉 ¿Superaste las dos partes? Bloque 5 completado. La biblioteca estándar ya está a tu servicio: ficheros, fechas, estadísticas, regex, JSON/CSV y entornos virtuales. Con esto entras de lleno en el Data Science del bloque 6. 🐍🔥