Pregunta 1¿Cuál es la forma recomendada de construir rutas que no se rompan ni en Windows ni en Linux?
os y pathlib — Rutas de archivos y operaciones con directorios
Aprende los módulos os.path y pathlib de Python desde cero. Construye rutas independientes del SO, lista y recorre directorios recursivamente, y descompón rutas en piezas con objetos Path — todo práctico.
Dos módulos manejan rutas de archivos y directorios — el más antiguo os.path y el más nuevo y legible pathlib. Este artículo recorre la construcción de rutas independientes del SO, el listado y la travesía recursiva de directorios, y la descomposición de rutas en piezas con objetos Path, en ese orden.
os.path — Construir rutas independientes del SO
Los separadores de ruta varían según el SO. Windows usa \ (barra invertida), mientras que Linux y macOS usan /. Hardcodear `"data/sales/2024.csv"` directamente en tu código funciona en Linux y Mac, pero Windows puede leer mal la ruta en tiempo de ejecución.
Si separas las partes y se las pasas a os.path.join("data", "sales", "2024.csv"), Python elige el separador correcto al vuelo según el SO en el que esté corriendo.
/ en Linux / Mac y a \ en Windows. No hornees los caracteres separadores a mano — ese es el truco para mantenerse portátil.| Función | Significado | Ejemplo |
|---|---|---|
| os.path.join(*parts) | Une rutas con el separador del SO | join('data', 'sales') → 'data/sales' |
| os.path.exists(p) | Si la ruta existe | True / False |
| os.path.isfile(p) | Si es un archivo (no un directorio) | True / False |
| os.path.isdir(p) | Si es un directorio | True / False |
| os.path.basename(p) | El nombre final del archivo o carpeta | basename('data/x.csv') → 'x.csv' |
| os.path.dirname(p) | La ruta padre con la cola eliminada | dirname('data/x.csv') → 'data' |
| os.path.splitext(p) | Separa la extensión | splitext('x.csv') → ('x', '.csv') |
Práctica 2 — Separar nombre y extensión con basename y splitext
No metas todo en una línea — asigna paso a paso a variables intermedias y separa el nombre del archivo de su extensión. basename saca el nombre final del archivo de una ruta completa y splitext divide ese nombre en una tupla (nombre, extensión).
os.listdir y os.walk — Listado de directorios y travesía recursiva
Cuando quieres traer el contenido de una carpeta a Python, usa os.listdir para un solo nivel y os.walk para descender recursivamente en subcarpetas. os.listdir devuelve una lista de nombres (tanto archivos como subcarpetas) directamente dentro de la carpeta que especificas, mientras que os.walk recorre el subárbol entero recursivamente y produce tuplas (ruta actual, lista de nombres de subcarpetas, lista de nombres de archivos) un nivel a la vez.
import os
# Un nivel: nombres directamente bajo 'data'
print(os.listdir("data"))
# → ['sales', 'inventory']
# Recursivo: recorre todo bajo 'data'
for dirpath, dirnames, filenames in os.walk("data"):
print(dirpath, filenames)
# → data ['sales', 'inventory'] []
# data/sales [] ['2024_q1.csv', '2024_q2.csv']
# data/inventory [] ['items.json']
glob — Coincidencia de patrones para recolectar archivos
Cuando quieres coger solo los archivos que coinciden con una condición — como solo archivos con extensión `.csv` — el módulo glob es el camino más corto. Escribe el objetivo como un patrón usando comodines como * (cualquier cadena) o ** (cualquier profundidad) y obtienes una lista de rutas coincidentes.
* coincide con cualquier cadena dentro del mismo nivel, ** cruza cualquier número de niveles (requiere recursive=True).import glob
# Archivos CSV directamente bajo data/sales
print(glob.glob("data/sales/*.csv"))
# → ['data/sales/2024_q1.csv', 'data/sales/2024_q2.csv']
# Búsqueda recursiva bajo data (** + recursive=True)
print(glob.glob("data/**/*.csv", recursive=True))
# → ['data/sales/2024_q1.csv', 'data/sales/2024_q2.csv']
El comodín ** de glob va emparejado con recursive=True
El doble asterisco en glob.glob("data/**/*.csv") es un comodín que cruza cualquier número de niveles. Pero sin recursive=True, se comporta como un * normal y no encontrará nada en carpetas más profundas. Pasa siempre ese argumento cuando quieras búsqueda recursiva.
pathlib.Path — Operaciones con rutas orientadas a objetos
Mientras que os.path era una biblioteca que manejaba las rutas como cadenas, desde Python 3.4 el enfoque recomendado es pathlib.Path, que trata las rutas en sí mismas como objetos. Construye una con Path("data/sales/2024_q1.csv") y puedes acceder a cada parte mediante atributos como .parent para la carpeta padre, .name para la pieza final, .stem para el nombre sin extensión y .suffix para la extensión.
os.path.dirname / basename / splitext por separado.from pathlib import Path
p = Path("data") / "sales" / "2024_q1.csv" # Une con el operador /
print(p) # data/sales/2024_q1.csv
print(p.parent) # data/sales
print(p.name) # 2024_q1.csv
print(p.stem) # 2024_q1
print(p.suffix) # .csv
print(p.exists()) # True
# Lee el contenido (un envoltorio sobre with open)
print(p.read_text()) # contenido del CSV
# Lista subcarpetas (equivalente a os.walk)
for sub in Path("data").rglob("*.csv"):
print(sub)
`os.path` es basado en cadenas, `pathlib.Path` es basado en objetos — ofrecen las mismas operaciones. La tabla de abajo mapea cada tarea entre ellos.
| Lo que quieres | Estilo os.path | Estilo pathlib |
|---|---|---|
| Unir | os.path.join('data', 'x.csv') | Path('data') / 'x.csv' |
| Carpeta padre | os.path.dirname(p) | p.parent |
| Nombre del archivo | os.path.basename(p) | p.name |
| Nombre sin extensión | Usa os.path.splitext(p)[0] | p.stem |
| Extensión | os.path.splitext(p)[1] | p.suffix |
| Comprobar existencia | os.path.exists(p) | p.exists() |
| Búsqueda recursiva | glob.glob('**/*.csv', recursive=True) | Path('.').rglob('*.csv') |
| Leer | with open(p) as f: f.read() | p.read_text() |
Elige pathlib para código nuevo
Pathlib es lo recomendado para código nuevo. Cuando APIs de bibliotecas más antiguas requieren rutas como cadena (algunos drivers de BD, por ejemplo), convierte con str(p). os.path no va a desaparecer, así que conocer ambos mapeos te deja cómodo leyendo código heredado también.
Verificación de conocimientos
Responde cada pregunta una a una.
Pregunta 2¿Cuál de las siguientes es la mejor para recorrer cada nivel de una carpeta recursivamente?
Pregunta 3Dado p = Path("data/sales/2024_q1.csv"), ¿cuál es el valor de p.stem?