TRBAJO CON RUTAS: pathlib y os.path¶
Python ofrece dos módulos para trabajar con rutas de ficheros y directorios:
pathlib(Python 3.4+): orientado a objetos, moderno y recomendadoos.path: módulo clásico, basado en cadenas de texto
Se verá con más detalle pathlib por ser la opción actualmente recomendada.
El módulo pathlib¶
pathlib representa las rutas como objetos de la clase Path. Esto permite encadenar operaciones de forma intuitiva y escribir código portable entre sistemas operativos sin preocuparse por los separadores de ruta.
El operador / entre objetos Path construye rutas de forma portable. En Windows de forma automática es cambiado por \
Ruta relativa al propio script¶
Un patrón muy habitual es construir rutas relativas al fichero .py que se está ejecutando, independientemente del directorio desde el que se lance el programa:
Path(__file__) es un objeto que apunta a la ruta del fichero que se está ejecutando, por ejemplo /ruta/proyecto/app/main.py. Al hacer Path(__file__).parent obtenemos un objeto de tipo PATH que apuntará a la carpeta del ejecutable /ruta/proyecto/app.
- BASE se define como constante porque su valor se calcula una vez y no debería cambiar durante la ejecución
Path(".") vs Path(__file__).parent¶
Ambas formas son válidas, pero sirven para propósitos distintos.
Vamos a verlo con un ejemplo, supongamos que tenemos un script en C:\Users\Ana\proyecto\scripts\demo.py y lo ejecutas desde C:\Users\Ana:
Path(".") |
Path(__file__).parent |
|
|---|---|---|
| Apunta a | C:\Users\Ana (directorio actual) |
C:\Users\Ana\proyecto\scripts (carpeta del script) |
| Cambia según | Desde dónde se lanza el programa | Nunca — siempre es la carpeta del .py |
| Úsar para | Ficheros del usuario en su directorio de trabajo | Recursos del propio programa (datos, config, plantillas) |
# Para listar ficheros donde el usuario está trabajando
for f in Path(".").glob("*.csv"):
print(f.name)
# Para cargar datos que vienen con el proyecto
BASE = Path(__file__).parent
config = BASE / "config" / "ajustes.json"
Operaciones básicas con pathlib¶
Comprobar existencia¶
Obtener partes de la ruta¶
Crear directorios¶
Listar ficheros de un directorio¶
Para filtrar aplicando patrones comodín, se usa glob(). El método glob devuelve un iterador (objeto que te da elementos uno a uno) con los archivos que cumplen con el patrón.
Por ejemplo si queremos filtrar por extensión:
- Convertimos en lista el iterador para poder recorrerlo con
for/in
De forma resumida. Patrones que podemos aplicar:
base = Path("proyecto")
base.glob("*.txt") # * -> cualquier secuencia: todos los .txt en esa carpeta
base.glob("foto?.jpg") # ? -> un carácter: foto1.jpg, fotoA.jpg
base.glob("archivo[12].csv") # [abc] -> un carácter del conjunto: archivo1.csv, archivo2.csv
base.glob("tema[1-5].md") # [a-z] -> un carácter en rango: tema1.md ... tema5.md
base.glob("[!._]*") # [!abc] -> un carácter fuera del conjunto: no empieza por . ni _
base.glob("**/*.py") # ** -> búsqueda recursiva: todos los .py en carpeta actual y subcarpetas
base.rglob("*.py") # recursiva también (equivalente práctico a **/*.py)
globviene de global (en Unix), y se refiere a la expansión de patrones con comodines para encontrar archivos/rutas.
Leer y escribir directamente en ficheros con pathlib¶
Path tiene métodos para leer y escribir sin necesidad de open():
Investiga: Por qué
read_text()ywrite_text()son convenientes para operaciones simples como lecturas línea a línea o escrituras incrementales y deberíamos seguir usandoopen()conwith.
El módulo os.path¶
El módulo clásico os.path trabaja con rutas como cadenas de texto. Aunque pathlib es preferible en código nuevo, es importante conocerlo porque aparece en mucho código existente (legacy).
Para construir rutas portables con os.path:
Comparativa pathlib vs os.path¶
| Operación | pathlib |
os.path |
|---|---|---|
| Construir ruta | Path("a") / "b" |
os.path.join("a", "b") |
| ¿Existe? | ruta.exists() |
os.path.exists(ruta) |
| ¿Es fichero? | ruta.is_file() |
os.path.isfile(ruta) |
| Nombre del fichero | ruta.name |
os.path.basename(ruta) |
| Directorio padre | ruta.parent |
os.path.dirname(ruta) |
| Extensión | ruta.suffix |
os.path.splitext(ruta)[1] |
| Leer texto | ruta.read_text() |
— |
mala práctica: concatenar rutas con strings
Usa pathlib en código nuevo
A partir de Python 3.6, open() y la mayoría de funciones que aceptan rutas también aceptan objetos Path directamente. No hay ninguna razón para usar concatenación de strings en código moderno.