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:
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:
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']
pathlib para rutas (más legible y multiplataforma) y deja
os.path solo para compatibilidad con código antiguo.Tiempo, math, random y statistics
2.1 · datetime
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
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.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:
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
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.
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):
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")
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
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)
open(..., "w") para CSV usa newline="": evita saltos de línea
extra en Windows. Parece raro pero es obligatorio.4.3 · JSON en profundidad
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)
itertools, functools y entornos virtuales
5.1 · itertools: iteradores potentes
product (producto cartesiano), combinations (combinaciones) y
cycle/islice ahorran bucles manuales:
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é
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:
$ 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
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.✍️ 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.logcon 10+ líneas tipo"2026-09-01 10:00:10 INFO Servicio iniciado"(varía INFO/ERROR/WARN). - Lee el fichero con
Pathy códigoutf-8. - Con
re, extrae el nivel de cada línea. - Con
Counter, cuenta cuántos INFO, ERROR y WARN hay y muéstralo ordenado conmost_common. - Cuenta también en qué fecha hubo más errores (usa slicing de la fecha).
- Guardar el resumen en
resumen.jsonconjson.dump. - Un
try/except FileNotFoundErrorcon 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)
📝 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 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