Question 1Quelle est la façon recommandée de construire des chemins qui ne cassent pas sur Windows ou Linux ?
os et pathlib — Chemins de fichiers et opérations sur les dossiers
Apprends les modules os.path et pathlib de Python depuis les bases. Construis des chemins indépendants de l'OS, liste et parcours récursivement les dossiers, et décompose les chemins en morceaux avec les objets Path — le tout en pratique.
Deux modules s'occupent des chemins de fichiers et des dossiers — l'ancien os.path et le plus récent et plus lisible pathlib. Cet article parcourt la construction de chemins indépendante de l'OS, le listage de dossier et le parcours récursif, et la décomposition des chemins en morceaux avec les objets Path, dans cet ordre.
os.path — Construire des chemins indépendants de l'OS
Les séparateurs de chemins diffèrent selon l'OS. Windows utilise \ (antislash), tandis que Linux et macOS utilisent /. Coder en dur `"data/sales/2024.csv"` directement dans ton code fonctionne sur Linux et Mac, mais Windows peut mal lire le chemin à l'exécution.
Si tu sépares les parties et les passes à os.path.join("data", "sales", "2024.csv"), Python choisit le bon séparateur à la volée selon l'OS sur lequel il tourne.
/ sur Linux / Mac et \ sur Windows. Ne grave pas les caractères de séparation à la main — c'est l'astuce pour rester portable.| Fonction | Signification | Exemple |
|---|---|---|
| os.path.join(*parts) | Joint les chemins avec le séparateur de l'OS | join('data', 'sales') → 'data/sales' |
| os.path.exists(p) | Si le chemin existe | True / False |
| os.path.isfile(p) | Si c'est un fichier (pas un dossier) | True / False |
| os.path.isdir(p) | Si c'est un dossier | True / False |
| os.path.basename(p) | Le nom de fichier ou de dossier final | basename('data/x.csv') → 'x.csv' |
| os.path.dirname(p) | Le chemin parent sans la fin | dirname('data/x.csv') → 'data' |
| os.path.splitext(p) | Sépare l'extension | splitext('x.csv') → ('x', '.csv') |
Pratique 2 — Séparer le nom et l'extension avec basename et splitext
Ne mets pas tout sur une seule ligne — affecte étape par étape dans des variables intermédiaires et sépare le nom de fichier de son extension. basename extrait le nom de fichier final d'un chemin complet, et splitext sépare ce nom en un tuple (nom, extension).
os.listdir et os.walk — Listage de dossier et parcours récursif
Quand tu veux importer le contenu d'un dossier dans Python, utilise os.listdir pour un seul niveau et os.walk pour descendre récursivement dans les sous-dossiers. os.listdir retourne une liste de noms (à la fois fichiers et sous-dossiers) directement à l'intérieur du dossier que tu spécifies, tandis que os.walk parcourt toute la sous-arborescence récursivement et produit des tuples (chemin courant, liste des noms de sous-dossiers, liste des noms de fichiers) un niveau à la fois.
import os
# Un niveau : noms directement sous 'data'
print(os.listdir("data"))
# → ['sales', 'inventory']
# Récursif : parcourir tout sous '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 — Filtrage par motif pour collecter des fichiers
Quand tu veux saisir uniquement les fichiers qui correspondent à une condition — comme uniquement les fichiers avec l'extension `.csv` — le module glob est le chemin le plus court. Écris la cible comme un motif en utilisant des jokers comme * (n'importe quelle chaîne) ou ** (n'importe quelle profondeur) et tu récupères une liste de chemins correspondants.
* correspond à n'importe quelle chaîne dans le même niveau, ** traverse n'importe quel nombre de niveaux (nécessite recursive=True).import glob
# Fichiers CSV directement sous data/sales
print(glob.glob("data/sales/*.csv"))
# → ['data/sales/2024_q1.csv', 'data/sales/2024_q2.csv']
# Recherche récursive sous data (** + recursive=True)
print(glob.glob("data/**/*.csv", recursive=True))
# → ['data/sales/2024_q1.csv', 'data/sales/2024_q2.csv']
Le joker ** de glob s'associe à recursive=True
Le double astérisque dans glob.glob("data/**/*.csv") est un joker qui traverse n'importe quel nombre de niveaux. Mais sans recursive=True, il se comporte comme un * ordinaire et ne trouvera rien dans les dossiers plus profonds. Passe toujours cet argument quand tu veux une recherche récursive.
pathlib.Path — Opérations de chemin orientées objet
Alors que os.path était une bibliothèque qui gère les chemins comme des chaînes, depuis Python 3.4 l'approche recommandée est pathlib.Path, qui traite les chemins eux-mêmes comme des objets. Construis-en un avec Path("data/sales/2024_q1.csv") et tu peux accéder à chaque partie via des attributs comme .parent pour le dossier parent, .name pour le morceau final, .stem pour le nom sans extension, et .suffix pour l'extension.
os.path.dirname / basename / splitext séparément.from pathlib import Path
p = Path("data") / "sales" / "2024_q1.csv" # Joindre avec l'opérateur /
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
# Lire le contenu (un wrapper autour de with open)
print(p.read_text()) # Contenu CSV
# Lister les sous-dossiers (équivalent à os.walk)
for sub in Path("data").rglob("*.csv"):
print(sub)
`os.path` est basé sur les chaînes, `pathlib.Path` est basé sur les objets — ils offrent les mêmes opérations. Le tableau ci-dessous fait correspondre chaque tâche entre eux.
| Ce que tu veux | Style os.path | Style pathlib |
|---|---|---|
| Joindre | os.path.join('data', 'x.csv') | Path('data') / 'x.csv' |
| Dossier parent | os.path.dirname(p) | p.parent |
| Nom de fichier | os.path.basename(p) | p.name |
| Nom sans extension | Utiliser os.path.splitext(p)[0] | p.stem |
| Extension | os.path.splitext(p)[1] | p.suffix |
| Vérification d'existence | os.path.exists(p) | p.exists() |
| Recherche récursive | glob.glob('**/*.csv', recursive=True) | Path('.').rglob('*.csv') |
| Lecture | with open(p) as f: f.read() | p.read_text() |
Choisis pathlib pour le nouveau code
Pathlib est recommandé pour le nouveau code. Quand des API de bibliothèques plus anciennes exigent des chemins en chaînes (certains pilotes de BD, par exemple), convertis avec str(p). os.path n'est pas près de partir, donc connaître les deux correspondances te garde à l'aise pour lire aussi le code legacy.
Vérification des connaissances
Répondez à chaque question une par une.
Question 2Lequel des suivants convient le mieux pour parcourir chaque niveau d'un dossier récursivement ?
Question 3Étant donné p = Path("data/sales/2024_q1.csv"), quelle est la valeur de p.stem ?