Tutorial

Comment utiliser le module pathlib pour manipuler les chemins des systèmes de fichiers en Python 3

PythonDevelopment

L'auteur a choisi le COVID-19 Relief Fund pour recevoir un don dans le cadre du programme Write for DOnations.

Introduction

Python 3 inclut le module pathlib, qui permet de manipuler les chemins des systèmes de fichiers de manière agnostique, quel que soit le système d'exploitation. pathlib est similaire au module os.path, mais pathlib offre un niveau d'interface supérieur — et souvent plus pratique — qu’os.path.

Nous pouvons identifier des fichiers sur un ordinateur avec des chemin hiérarchiques. Par exemple, nous pourrions identifier le fichier wave.txt sur un ordinateur avec ce chemin : /Users/sammy/ocean/wave.txt. Les systèmes d'exploitation représentent les chemins de manière légèrement différente. Windows peut représenter le chemin d'accès au fichier wave.txt comme ceci, C:\Users\sammy\ocean\wave.txt.

Vous pouvez trouver le module pathlib utile si dans votre programme Python vous créez ou déplacez des fichiers dans le système de fichiers, listez des fichiers sur le système de fichiers qui correspondent tous à une extension ou un modèle donnés, ou créez des chemins de fichiers appropriés du système d'exploitation basés sur des collections de chaînes de caractères. Bien que vous puissiez utiliser d'autres outils (comme le module os.path) pour accomplir plusieurs de ces tâches, le module pathlib vous permet d'effectuer ces opérations avec un degré de lisibilité élevé et une quantité minimale de code.

Dans ce tutoriel, nous aborderons certaines des façons d'utiliser le module pathlib pour représenter et manipuler les chemins du système de fichiers.

Conditions préalables

Pour tirer le meilleur parti de ce tutoriel, il est recommandé d'être familiarisé avec la  programmation en Python 3. Vous pouvez consulter ces tutoriels pour obtenir les informations de base nécessaires :

Construire des instances Path

Le module pathlib fournit plusieurs classes, mais l'une des plus importantes est la classe Path. Les instances de la classe Path représentent un chemin d'accès à un fichier ou un répertoire du système de fichiers de notre ordinateur.

Par exemple, le code suivant instancie une instance Path qui représente une partie du chemin d'accès à un fichier wave.txt :

from pathlib import Path

wave = Path("ocean", "wave.txt")
print(wave)

Si nous exécutons ce code, nous obtiendrons le résultat suivant :

Output
ocean/wave.txt

from pathlib import Path rend la classe Path disponible pour notre programme. Ensuite, Path("ocean", "wave.txt") instance une instance nouvelle Path. L'impression de la sortie montre que Python a ajouté le séparateur approprié du système d'exploitation / entre les deux composants de chemin que nous lui avons donné : "ocean"et "wave.txt".

Remarque : En fonction de votre système d'exploitation, votre résultat peut varier légèrement par rapport aux exemples de sorties présentés dans ce tutoriel. Si vous utilisez Windows, par exemple, votre résultat pour ce premier exemple ressemblera peut-être à ocean\wave.txt.

À présent, l'objet Path assigné à la variable wave contient un chemin relatif. En d'autres termes, ocean/wave.txt pourrait exister à plusieurs emplacements de notre système de fichiers. À titre d'exemple, il peut exister dans /Users/user_1/ocean/wave.txt ou /Users/user_2/research/ocean/wave.txt, mais nous n'avons pas préciséà quel endroit exactement nous faisons référence. Un chemin absolu, en revanche, renvoie sans ambiguïté à un seul emplacement du système de fichiers.

Vous pouvez utiliser Path.home() pour obtenir le chemin absolu du répertoire d'accueil de l'utilisateur actuel :

home = Path.home()
wave_absolute = Path(home, "ocean", "wave.txt")
print(home)
print(wave_absolute)

Si nous exécutons ce code, nous obtiendrons en gros le résultat suivant :

Output
/Users/sammy /Users/sammy/ocean/wave.txt

Remarque : Comme mentionné précédemment, votre sortie varie en fonction de votre #système d'exploitation. Votre répertoire d'accueil, bien sûr, sera également différent de /Users/sammy.

Path.home() renvoie une instance Path avec un chemin absolu vers le répertoire d'accueil de l'utilisateur actuel. Nous passons ensuite dans cette instance Path et les chaînes "ocean" et "wave.txt" dans un autre constructeur Path pour créer un chemin absolu vers le fichier wave.txt. La sortie montre que la première ligne est le répertoire d'accueil, et la deuxième ligne est le répertoire d'accueil plus ocean/wave.txt.

Cet exemple illustre également une caractéristique importante de la classe Path : le constructeur Path accepte les chaînes et les objets Path préexistants.

Examinons de plus près le support des chaînes et des objets Path dans le constructeur Path  :

shark = Path(Path.home(), "ocean", "animals", Path("fish", "shark.txt"))
print(shark)

Si nous exécutons ce code Python, nous obtiendrons un résultat similaire au suivant :

Output
/Users/sammy/ocean/animals/fish/shark.txt

shark est un Path vers un fichier que nous avons construit en utilisant les objets Path (Path.home() et Path("fish", "shark.txt")) et les chaînes ("ocean" et "animals"). Le constructeur Path traite intelligemment les deux types d'objets et les joint de manière propre en utilisant le séparateur du système d'exploitation approprié, dans ce cas /.

Accéder aux attributs de fichier

Maintenant que nous avons appris comment construire des instances Path, examinons comment vous pouvez utiliser ces instances pour accéder aux informations sur un fichier.

Nous pouvons utiliser les attributs name et suffix pour accéder aux noms de fichier et aux suffixes :

wave = Path("ocean", "wave.txt")
print(wave)
print(wave.name)
print(wave.suffix)

En exécutant ce code, nous obtiendrons un résultat similaire à ce qui suit :

Output
/Users/sammy/ocean/wave.txt wave.txt .txt

Cette sortie montre que le nom du fichier à la fin de notre chemin est wave.txt et le suffixe de ce fichier est .txt.

Les instances Path offrent également la fonction with_name, qui permet de créer de manière transparente un nouvel objet Path portant un nom différent :

wave = Path("ocean", "wave.txt")
tides = wave.with_name("tides.txt")
print(wave)
print(tides)

Si nous exécutons ce code, nous obtiendrons le résultat suivant :

ocean/wave.txt
ocean/tides.txt

Le code construit d'abord une instance Path qui pointe vers un fichier nommé wave.txt. Ensuite, nous appelons la méthode with_name sur wave pour renvoyer une seconde instance Path qui pointe vers un nouveau fichier nommé tides.txt. La partie du chemin correspondant au répertoire ocean/ reste inchangée, ce qui fait que le chemin final devient ocean/tides.txt

Accéder aux ascendants

Il est parfois utile d'accéder à des répertoires qui contiennent un chemin d'accès donné. Prenons un exemple :

shark = Path("ocean", "animals", "fish", "shark.txt")
print(shark)
print(shark.parent)

Si nous exécutons ce code, nous obtiendrons un résultat qui ressemble au suivant :

Output
ocean/animals/fish/shark.txt ocean/animals/fish

L'attribut parent d'une instance Path renvoie l'ascendant le plus immédiat d'un chemin de fichier donné. Dans ce cas, il renvoie le répertoire qui contient le fichier shark.txt : ocean/animals/fish.

Nous pouvons accéder à l'attribut parent plusieurs fois de suite pour remonter l'arbre d'ascendance d'un fichier donné :

shark = Path("ocean", "animals", "fish", "shark.txt")
print(shark)
print(shark.parent.parent)

Si nous exécutons ce code, nous obtiendrons le résultat suivant :

Output
ocean/animals/fish/shark.txt ocean/animals

La sortie est similaire à la sortie précédente, mais maintenant nous avons traversé un autre niveau plus élevé en accédant à .parent une seconde fois. Deux répertoires plus haut que shark.txt nous avons le répertoire ocean/animals.

Utiliser Glob pour lister les fichiers

Il est également possible d'utiliser la classe Path pour lister les fichiers à l'aide de la méthode glob.

Supposons que nous avons une structure de répertoire qui ressemblait à ceci :

└── ocean
    ├── animals
    │   └── fish
    │       └── shark.txt
    ├── tides.txt
    └── wave.txt

Le répertoire ocean contient les fichiers tides.txt et wave.txt. Nous avons un fichier nommé shark.txt imbriqué sous le répertoire ocean, un répertoire animals et un répertoire fish : ocean/animals/fish.

Pour lister tous les fichiers .txt du répertoire ocean, nous pourrions dire :

for txt_path in Path("ocean").glob("*.txt"):
    print(txt_path)

Ce code donnerait un résultat du type :

Output
ocean/wave.txt ocean/tides.txt

Le modèle glob "*.txt" trouve tous les fichiers se terminant par .txt. Comme l'exemple de code exécute ce glob dans le répertoire ocean, il renvoie les deux fichiers .txt du répertoire ocean : wave.txt et tides.txt.

Remarque : Si vous souhaitez dupliquer les sorties indiquées dans cet exemple, vous devrez imiter la structure de répertoire illustrée ici sur votre ordinateur.

Nous pouvons également utiliser la méthode glob de manière récursive. Pour lister tous les fichiers .txt du répertoire ocean et tous ses sous-répertoires, nous pourrions dire :

for txt_path in Path("ocean").glob("**/*.txt"):
    print(txt_path)

Si nous exécutons ce code, nous obtiendrions le résultat suivant :

Output
ocean/wave.txt ocean/tides.txt ocean/animals/fish/shark.txt

La partie ** du modèle glob correspondra à ce répertoire et tous les répertoires en dessous, de manière récursive. Donc, non seulement nous avons les fichiers wave.txt et tides.txt dans la sortie, mais nous recevons également le fichier shark.txt qui a été imbriqué sous ocean/animals/fish.

Calculer les chemin relatifs

Nous pouvons utiliser la méthode Path.relative_to pour calculer les chemins par rapport aux autres. La méthode relative_to est utile lorsque, par exemple, vous souhaitez récupérer une partie d'un long chemin de fichier.

Prenons le cas du code suivant :

shark = Path("ocean", "animals", "fish", "shark.txt")
below_ocean = shark.relative_to(Path("ocean"))
below_animals = shark.relative_to(Path("ocean", "animals"))
print(shark)
print(below_ocean)
print(below_animals)

Si nous exécutons ce code, nous obtiendrons le résultat suivant :

Output
ocean/animals/fish/shark.txt animals/fish/shark.txt fish/shark.txt

La méthode relative_to renvoie un nouvel objet Path relatif à l'argument donné. Dans notre exemple, nous calculons le Path d'accès à shark.txt par rapport au répertoire ocean, puis par rapport aux répertoires ocean et animals.

Si la fonction relative_to ne peut pas calculer de réponse parce que nous lui fournissons un chemin non relié, elle génère une ValueError :

shark = Path("ocean", "animals", "fish", "shark.txt")
shark.relative_to(Path("unrelated", "path"))

Nous obtiendrons une exception ValueError qui a été soulevée à partir de ce code et qui ressemblera à quelque chose comme ceci :

Output
Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/usr/local/lib/Python3.8/pathlib.py", line 899, in relative_to raise ValueError("{!r} does not start with {!r}" ValueError: 'ocean/animals/fish/shark.txt' does not start with 'unrelated/path'

unrelated/path n'est pas une partie de ocean/animals/fish/shark.txt, Python n'a donc aucun moyen pour de calculer un chemin relatif pour nous.

Conclusion

Le module pathlib est une partie puissante de la bibliothèque standard Python qui nous permet de manipuler rapidement les chemins du système de fichiers sur n'importe quel système d'exploitation. Dans ce tutoriel, nous avons appris à utiliser certains des utilitaires clés de pathlib pour accéder aux attributs de fichier, lister les fichiers avec des modèles glob, et parcourir les fichiers et les répertoires parents.

Le module pathlib propose des classes et des utilitaires supplémentaires que nous n'avons pas abordés dans ce tutoriel. Maintenant que vous disposez d'une base de référence, vous pouvez utiliser la documentation du module pathlib pour en savoir plus sur d'autres classes et utilitaires disponibles.

Si vous souhaitez utiliser d'autres bibliothèques Python, consultez les tutoriels suivants :

Creative Commons License