programa
Guía completa para utilizar pathlib en Python para la manipulación del sistema de archivos
Hasta hace poco, la manipulación del sistema de archivos en Python era notoriamente difícil. Los desarrolladores solían tener problemas con las rutas de archivo incorrectas, que eran propensas a errores porque requerían largas cadenas como entradas. Además, los desarrolladores informaron de que su código se rompía con frecuencia debido a incoherencias en los distintos sistemas operativos.
Por suerte, en la versión 3.4 de Python, los desarrolladores introdujeron el módulo pathlib
en la biblioteca estándar. pathlib
proporciona una solución elegante para manejar las rutas del sistema de archivos mediante un enfoque orientado a objetos que se esperaba desde hace tiempo, y además garantiza un comportamiento agnóstico respecto a la plataforma.
Este completo tutorial te enseñará las funciones del módulo pathlib
para ayudarte en tus interacciones diarias con tu sistema de archivos. Utilizando pathlib
, te beneficiarás de flujos de trabajo eficientes y de una fácil recuperación de datos. pathlib
ha madurado significativamente a lo largo de los años, y nos hemos mantenido al día para que tú no tengas que hacerlo. Empecemos.
Módulo Python os vs. pathlib
Antes de Python 3.4, la forma más tradicional de manejar las rutas de los archivos era utilizando el módulo os
. Aunque el módulo os
fue muy eficaz en su día, ha empezado a mostrar su vejez.
Podemos mostrar el valor único de pathlib
considerando una tarea común en la ciencia de datos: cómo encontrar todos los archivos png
dentro de un directorio dado y todos sus subdirectorios.
Si utilizáramos el módulo os
, podríamos escribir el código siguiente:
import os
dir_path = "/home/user/documents"
files = [
os.path.join(dir_path, f)
for f in os.listdir(dir_path)
if os.path.isfile(os.path.join(dir_path, f)) and f.endswith(".png")
]
Aunque este código resuelve la tarea inmediata de encontrar nuestros archivos png
, revela varias desventajas importantes del módulo os
. Para empezar, el código es largo y casi ilegible, lo que es una pena, teniendo en cuenta que se trata de una operación relativamente sencilla. Como segundo punto, nuestro código presupone el conocimiento de las comprensiones de listas, lo que no debe darse por supuesto. Como tercer punto, el código implica operaciones con cadenas, que son propensas a errores. Y además de todo esto, el código no es muy conciso.
Si, en cambio, utilizáramos el módulo pathlib, nuestro código sería mucho más sencillo. Como hemos mencionado, pathlib
proporciona un enfoque orientado a objetos para manejar las rutas del sistema de archivos. Echa un vistazo:
from pathlib import Path
# Create a path object
dir_path = Path(dir_path)
# Find all text files inside a directory
files = list(dir_path.glob("*.png"))
Esta programación orientada a objetos organiza el código en torno a los objetos y sus interacciones, lo que conduce a un código más modular, reutilizable y mantenible. Si no estás familiarizado con la programación orientada a objetos, merece la pena que aprendas con nuestrocurso Programación Python Orientada a Objetos.
Trabajar con objetos Path en Python
La biblioteca pathlib
gira en torno a lo que se denominan objetos Path
, que representan las rutas del sistema de archivos de forma estructurada e independiente de la plataforma.
Anteriormente en este tutorial, trajimos la clase Path
del módulo pathlib
a nuestro espacio de nombres actual utilizando la siguiente línea de código:
from pathlib import Path
Después de llamar a la clase Path
desde pathlib
, podemos crear objetos Path
de varias formas, incluyendo desde cadenas, desde otros objetos Path
, desde el directorio de trabajo actual y desde el directorio de inicio.
Echemos un vistazo a cada uno de ellos.
Crear objetos ruta a partir de cadenas
Podemos crear un objeto Path
pasando una cadena que represente una ruta del sistema de archivos a una variable. Convierte la representación de cadena de la ruta del archivo en un objeto Path
.
file_path_str = "data/union_data.csv"
data_path = Path(file_path_str)
Crear objetos trayectoria a partir de otros objetos trayectoria
Los objetos existentes en Path
pueden servir como bloques de construcción para crear nuevas rutas.
Lo hacemos combinando una ruta base, un directorio de datos y un nombre de archivo en una única ruta de archivo. Tenemos que acordarnos de utilizar una barra oblicua cuando proceda para ampliar nuestros objetos Path
.
base_path = Path("/home/user")
data_dir = Path("data")
# Combining multiple paths
file_path = base_path / data_dir / "prices.csv"
print(file_path)
'/home/user/data/prices.csv'
Crear objetos de ruta desde el directorio de trabajo actual
Aquí asignamos el directorio de trabajo actual a la variable cwd
utilizando el método Path.cwd()
. A continuación, podemos recuperar la ruta del directorio de trabajo actual donde se está ejecutando nuestro script.
cwd = Path.cwd()
print(cwd)
'/home/bexgboost/articles/2024/4_april/8_pathlib'
Crear objetos de ruta desde el directorio de trabajo inicial
Podemos construir una ruta combinando nuestro directorio personal con subdirectorios adicionales. Aquí estamos combinando nuestro directorio personal con los subdirectorios "descargas" y "proyectos".
home = Path.home()
home / "downloads" / "projects"
PosixPath('/home/bexgboost/downloads/projects')
Una nota importante: La clase Path
en sí no realiza ninguna operación del sistema de archivos, como validación de rutas, creación de directorios o archivos. Está diseñado para representar y manipular trayectorias. Para interactuar realmente con el sistema de archivos (comprobar la existencia, leer/escribir archivos), tendremos que utilizar métodos especiales de los objetos Path
y, para algunos casos avanzados, obtener ayuda del módulo os
.
Trabajar con componentes de ruta en Python
Los atributos de una ruta de archivo son varias propiedades y componentes de una ruta de archivo que ayudan a identificar y gestionar archivos y directorios dentro de un sistema de archivos. Al igual que una dirección física tiene diferentes partes, como el número de la calle, la ciudad, el país y el código postal, una ruta de un sistema de archivos puede descomponerse en componentes más pequeños. pathlib
nos permite acceder a estos componentes y manipularlos utilizando atributos de ruta mediante la notación de puntos.
Trabajar con el directorio raíz
La raíz es el directorio superior de un sistema de archivos. En los sistemas tipo Unix, se representa con una barra oblicua (/
). En Windows, suele ser una letra de unidad seguida de dos puntos, como C:
.
image_file = home / "downloads" / "midjourney.png"
image_file.root
'/'
Trabajar con el directorio principal
El padre contiene el archivo o directorio actual. es un nivel superior relativo al directorio o archivo actual.
image_file.parent
PosixPath('/home/bexgboost/downloads')
Trabajar con el nombre del archivo
Este atributo devuelve el nombre completo del archivo, incluida la extensión, en forma de cadena.
image_file.name
'midjourney.png'
Trabajar con el sufijo del archivo
El atributo sufijo devuelve la extensión del archivo, incluido el punto, como una cadena (o una cadena vacía si no hay extensión).
image_file.suffix
'.png'
Trabajar con la raíz del archivo
La raíz devuelve el nombre del archivo sin la extensión. Trabajar con el tallo puede ser útil al convertir archivos a distintos formatos.
image_file.stem
'midjourney'
Nota: En un Mac, las rutas de los archivos distinguen entre mayúsculas y minúsculas, por lo que /Users/username/Documents
y /users/username/documents
serían diferentes.
El atributo pathlib partes
Podemos utilizar el atributo .parts
para dividir un objeto Path
en sus componentes.
image_file.parts
('/', 'home', 'bexgboost', 'downloads', 'midjourney.png')
El atributo pathlib padres
El atributo parents
, que devuelve un generador, convierte estos componentes en objetos Path
.
list(image_file.parents)
[PosixPath('/home/bexgboost/downloads'),
PosixPath('/home/bexgboost'),
PosixPath('/home'),
PosixPath('/')]
Operaciones comunes con pathlib
Path
tienen muchos métodos que te permiten interactuar eficazmente con los directorios y su contenido. Veamos cómo realizar algunas de las operaciones más habituales.
Listado de directorios
El método iterdir()
te permite iterar sobre todos los archivos y subdirectorios de una carpeta. Es especialmente útil para procesar todos los archivos de un directorio o realizar operaciones en cada entrada.
cwd = Path.cwd()
for entry in cwd.iterdir():
# Process the entry here
...
# print(entry)
Como iterdir()
devuelve un iterador, las entradas se recuperan bajo demanda a medida que avanzas por el bucle.
El método is_dir()
El método is_dir()
devuelve True
si la ruta apunta a un directorio, False
en caso contrario.
for entry in cwd.iterdir():
if entry.is_dir():
print(entry.name)
.ipynb_checkpoints
data
images
El método is_file()
El método .is_file()
devuelve True
si la ruta apunta a un archivo, False
en caso contrario.
for entry in cwd.iterdir():
if entry.is_file():
print(entry.suffix)
.ipynb
.txt
El método existe()
Como los objetos Path
sólo representan rutas, a veces necesitas comprobar si existe una ruta utilizando el método .exists()
:
El método .exists() comprueba si existe una ruta. Esto es útil porque los objetos Path
pueden representar archivos y directorios que pueden o no estar realmente presentes en el sistema de archivos.
image_file.exists()
False
Crear y eliminar rutas
pathlib
también ofrece funciones para crear y borrar archivos y directorios. Veamos cómo.
El método mkdir()
El método mkdir()
crea un nuevo directorio en la ruta especificada. Por defecto, crea el directorio en el directorio de trabajo actual.
from pathlib import Path
data_dir = Path("new_data_dir")
# Create the directory 'new_data_dir' in the current working directory
data_dir.mkdir()
El método mkdir(padres=Verdadero)
El método mkdir(parents=True)
es especialmente útil cuando quieres crear una estructura de directorios en la que algunos directorios padre pueden no existir. Establecer parents=True
garantiza que se creen todos los directorios padre necesarios a lo largo del proceso.
sub_dir = Path("data/nested/subdirectory")
# Create 'data/nested/subdirectory', even if 'data' or 'nested' don't exist
sub_dir.mkdir(parents=True)
Ten en cuenta que mkdir()
lanza una excepción si ya existe un directorio con el mismo nombre.
Path('data').mkdir()
FileExistsError: [Errno 17] File exists: 'data'
El método unlink()
El método unlink()
borra permanentemente un archivo representado por el objeto Path
. Se recomienda comprobar si existe un archivo antes de ejecutar este método para evitar recibir un error.
to_delete = Path("data/prices.csv")
if to_delete.exists():
to_delete.unlink()
print(f"Successfully deleted {to_delete.name}")
Successfully deleted prices.csv
El método rmdir()
El método rmdir()
elimina un directorio vacío. Recuerda que rmdir()
sólo funciona para eliminar directorios vacíos. La forma más sencilla de borrar un directorio no vacío es utilizar la biblioteca shutil o el terminal.
empty_dir = Path("new_data_dir")
empty_dir.rmdir()
Nota: Ten cuidado al utilizar unlink()
o rmdir()
porque sus resultados son permanentes.
Manipulación avanzada de trayectorias
Pasemos a algunos conceptos avanzados de manipulación de trayectorias y cómo aplicarlos en la práctica utilizando pathlib
.
Rutas relativas vs. absolutas
Empezaremos por comprender las diferencias entre rutas absolutas y relativas, ya que surgen a menudo.
Caminos relativos
Las rutas relativas especifican la ubicación de un archivo o directorio respecto al directorio actual, de ahí la palabra relativa. Son breves y flexibles dentro de tu proyecto, pero pueden ser confusos si cambias el directorio de trabajo.
Por ejemplo, tengo una carpeta images en mi directorio de trabajo actual, que tiene el archivo midjourney.png
.
image = Path("images/midjourney.png")
image
PosixPath('images/midjourney.png')
El código anterior funciona ahora, pero si muevo el bloc de notas que estoy utilizando a una ubicación diferente, el fragmento se romperá porque la carpeta de imágenes no se movió con el bloc de notas.
Rutas absolutas
Las rutas absolutas especifican la ubicación completa de un archivo o directorio desde la raíz del sistema de archivos. Son independientes del directorio actual y ofrecen un punto de referencia claro para cualquier usuario en cualquier parte del sistema.
image_absolute = Path("/home/bexgboost/articles/2024/4_april/8_pathlib/images/midjourney.png")
image_absolute
PosixPath('/home/bexgboost/articles/2024/4_april/8_pathlib/images/midjourney.png')
Como puedes ver, las rutas absolutas pueden ser bastante largas, especialmente en proyectos complejos con estructuras de árbol anidadas. Por eso, la mayoría de la gente prefiere las rutas relativas, que son más cortas.
Método Resolver
pathlib
proporciona métodos para convertir rutas relativas en absolutas con el método resolve()
.
relative_image = Path("images/midjourney.png")
absolute_image = relative_image.resolve()
absolute_image
PosixPath('/home/bexgboost/articles/2024/4_april/8_pathlib/images/midjourney.png')
También podemos ir en sentido contrario: Si tenemos una ruta absoluta, podemos convertirla en relativa a partir de un directorio de referencia.
relative_path = Path.cwd()
absolute_image.relative_to(relative_path)
PosixPath('images/midjourney.png')
Globbing
Para ilustrar el globbing, podemos volver al ejemplo que presentamos al principio del artículo, en el que escribimos código para encontrar todos los archivos png
en un directorio determinado.
files = list(dir_path.glob("*.png"))
pathlib
utiliza el módulo incorporado .glob()
para buscar eficazmente archivos que coincidan con un patrón específico en cualquier directorio. Este módulo es muy útil cuando se procesan archivos con nombres o extensiones similares.
El método glob funciona aceptando como entrada una cadena de patrones que contiene comodines y devuelve un objeto generador que produce objetos Path
coincidentes bajo demanda:
-
*
: Coincide con cero o más caracteres. -
?
: Coincide con cualquier carácter. -
[]
: Coincide con un rango de caracteres encerrados entre paréntesis (por ejemplo, [a-z] coincide con cualquier letra minúscula).
Para ilustrarlo, intentemos encontrar todos los cuadernos Jupyter en mi directorio de artículos.
articles_dir = Path.home() / "articles"
# Find all scripts
notebooks = articles_dir.glob("*.ipynb")
# Print how many found
print(len(list(notebooks)))
0
El método .glob()
no encontró ningún cuaderno, lo que a primera vista parece sorprendente porque he escrito más de 150 artículos. La razón es que .glob()
sólo busca dentro del directorio dado, no en sus subdirectorios.
Podemos solucionarlo haciendo una búsqueda recursiva, para lo que necesitamos utilizar el método rglob()
, que tiene una sintaxis similar:
notebooks = articles_dir.rglob("*.ipynb")
print(len(list(notebooks)))
357
Esta vez, nuestro código encontró los 357 archivos.
Trabajar con archivos
Como hemos visto, los objetos Path
sólo representan archivos, pero no realizan operaciones con ellos. Sin embargo, disponen de ciertos métodos para las operaciones habituales con archivos. Veremos cómo utilizarlos en esta sección.
Lectura de archivos
La lectura del contenido de los archivos es una operación fundamental en muchas aplicaciones de Python. pathlib
proporciona cómodos métodos abreviados para leer archivos como texto o como bytes sin procesar.
El método read_text()
nos permite leer el contenido de un archivo de texto y cerrarlo.
file = Path("file.txt")
print(file.read_text())
This is sample text.
Para los archivos binarios, podemos utilizar en su lugar el método read_bytes()
.
image = Path("images/midjourney.png")
image.read_bytes()[:10]
b'\x89PNG\r\n\x1a\n\x00\x00'
Recuerda, cuando utilices un método read_*
, el tratamiento de errores es importante:
nonexistent_file = Path("gibberish.txt")
try:
contents = nonexistent_file.read_text()
except FileNotFoundError:
print("No such thing.")
No such thing.
Escribir archivos
Escribir en archivos es tan fácil como leer archivos. Para escribir archivos, tenemos el método write_text()
.
file = Path("file.txt")
file.write_text("This is new text.")
17
file.read_text()
'This is new text.'
Como vemos, el método write_text()
sobrescribe el texto. Aunque no hay modo de añadir texto para write_text()
, podemos utilizar read_text()
y write_text()
juntos para añadir texto al final del archivo.
old_text = file.read_text() + "\n"
final_text = "This is the final text."
# Combine old and new texts and write them back
file.write_text(old_text + final_text)
print(file.read_text())
This is new text.
This is the final text.
write_bytes()
funciona de forma similar. Para ilustrarlo, dupliquemos primero la imagen midjourney.png
con un nuevo nombre.
original_image = Path("images/midjourney.png")
new_image = original_image.with_stem("duplicated_midjourney")
new_image
PosixPath('images/duplicated_midjourney.png')
El método with_stem()
devuelve una ruta de archivo con un nombre de archivo diferente (aunque el sufijo sigue siendo el mismo). Esto nos permite leer una imagen original y escribir su contexto en una nueva imagen.
new_image.write_bytes(original_image.read_bytes())
1979612
Renombrar y mover archivos
Además de la función with_stem()
para renombrar la raíz de un archivo, pathlib
ofrece el método rename()
para renombrar de forma más completa.
file = Path("file.txt")
target_path = Path("new_file.txt")
file.rename(target_path)
PosixPath('new_file.txt')
rename()
acepta una ruta de destino, que puede ser una cadena u otro objeto ruta.
Para mover archivos, puedes utilizar la función replace()
, que también acepta una ruta de destino:
# Define the file to be moved
source_file = Path("new_file.txt")
# Define the location to put the file
destination = Path("data/new/location")
# Create the directories if they don't exist
destination.mkdir(parents=True)
# Move the file
source_file.replace(destination / source_file.name)
PosixPath('data/new/location/new_file.txt')
Crear archivos en blanco
pathlib
nos permite crear archivos en blanco utilizando el método touch
:
# Define new file path
new_dataset = Path("data/new.csv")
new_dataset.exists()
False
new_dataset.touch()
new_dataset.exists()
True
El método touch
está pensado originalmente para actualizar la hora de modificación de un archivo, por lo que también se puede utilizar en archivos existentes.
original_image.touch()
Cuando necesites reservar un nombre de archivo para utilizarlo más adelante, pero no tengas ningún contenido que escribir en él en ese momento, podemos utilizar el toque para crear un espacio en blanco. El método se inspiró en el comando de terminal táctil de Unix.
Permisos e información del sistema de archivos
Como punto final, aprenderemos a acceder a las características de los archivos utilizando el método .stat()
. Si estás familiarizado con os
, te darás cuenta de que este nuevo método tiene el mismo resultado que os.stat()
.
image_stats = original_image.stat()
image_stats
os.stat_result(st_mode=33188, st_ino=1950175, st_dev=2080, st_nlink=1, st_uid=1000, st_gid=1000, st_size=1979612, st_atime=1714664562, st_mtime=1714664562, st_ctime=1714664562)
También podemos recuperar el tamaño del archivo utilizando la notación con puntos.
image_size = image_stats.st_size
# File size in megabytes
image_size / (1024**2)
1.8879051208496094
Conclusión
La introducción del módulo pathlib
en Python 3.4 ha simplificado significativamente la manipulación del sistema de archivos para los desarrolladores. Al proporcionar un enfoque orientado a objetos para manejar las rutas de los archivos, pathlib
proporciona una forma estructurada y directa de representar las rutas del sistema de archivos. pathlib
también ofrece independencia de la plataforma, lo que significa que pathlib
maneja los separadores de rutas de forma coherente en diferentes sistemas operativos, de modo que nuestro código no se rompe en una máquina nueva. Por último, pathlib
ofrece un amplio conjunto de métodos concisos y expresivos para las operaciones habituales del sistema de archivos, como hemos visto.
Ten en cuenta que pathlib
representa una de las muchas y potentes bibliotecas incorporadas en Python. Si sigues nuestros cursos Científico de Datos con Python, Python Programming Skill Track e Introducción a Python para la Ciencia de Datos, dominarás un amplio conjunto de bibliotecas integradas para convertirte en un sólido programador de Python.
¡Gracias por leer!

Soy un creador de contenidos de ciencia de datos con más de 2 años de experiencia y uno de los mayores seguidores en Medium. Me gusta escribir artículos detallados sobre IA y ML con un estilo un poco sarcastıc, porque hay que hacer algo para que sean un poco menos aburridos. He publicado más de 130 artículos y un curso DataCamp, y estoy preparando otro. Mi contenido ha sido visto por más de 5 millones de ojos, 20.000 de los cuales se convirtieron en seguidores tanto en Medium como en LinkedIn.
Aprende Python con DataCamp
curso
Escribir código Python eficiente
curso