Cours de Python / Manipuler les chemins de fichiers avec pathlib.Path

pathlib.Path représente un chemin de fichier ou de dossier et assemble ses composants selon les règles du système d’exploitation. Un chemin relatif part du dossier de travail courant, qui peut être différent du dossier contenant votre script.

Assembler les chemins sans séparateurs manuels

Path("data") / "expenses.csv" combine deux composants sans insérer soi-même les antislashs Windows ni prévoir un séparateur différent par système. Construire cet objet ne crée ni dossier ni fichier : les opérations telles que mkdir() et write_text() accèdent effectivement au système de fichiers.

Path.cwd() donne le dossier de travail. Dans un script, Path(__file__).resolve().parent permet de repérer le dossier du fichier source résolu ; __file__ peut toutefois manquer dans une session interactive. Choisissez explicitement le dossier de référence selon l’interface de votre programme, au lieu de supposer que toutes ces positions coïncident.

La documentation officielle de pathlib décrit les propriétés, la recherche et les opérations de lecture ou d’écriture. La distinction entre contexte d’exécution et emplacement d’un module apparaît aussi dans la leçon sur les paquets et leur point d’entrée.

Créer et examiner un fichier d’exercice

Utilisez un nouveau dossier d’exercice vide : le programme crée lab-data/expenses.csv sous le dossier de travail et remplace son contenu si ce fichier existe déjà. Python 3 et sa bibliothèque standard suffisent. Enregistrez le bloc complet dans paths.py, en UTF-8, dans ce dossier.

Ouvrez le terminal dans le dossier d’exercice, avec l’environnement virtuel du projet activé, puis lancez python paths.py. Sur macOS ou Ubuntu hors environnement virtuel, utilisez python3 paths.py si votre interpréteur porte ce nom.

from pathlib import Path

base = Path("lab-data")
base.mkdir(exist_ok=True)
path = base / "expenses.csv"
path.write_text("name,amount\nlunch,8000\n", encoding="utf-8")
print(path.name, path.suffix, path.stem)
print(path.is_file(), base.is_dir())
print(sorted(p.name for p in base.glob("*.csv")))

Dans ce dossier initialement vide, le résultat attendu est :

expenses.csv .csv expenses
True True
['expenses.csv']

name est le nom complet expenses.csv, suffix est son dernier suffixe .csv et stem le nom sans ce suffixe, expenses. Les deux valeurs True confirment respectivement qu’un fichier et un dossier existent à ces chemins. La dernière ligne affiche les noms correspondants au motif *.csv, triés.

mkdir(exist_ok=True) tolère ici un dossier lab-data déjà présent, mais pas un fichier ordinaire du même nom. Le programme ne crée qu’un niveau de dossier. write_text utilise explicitement UTF-8 et écrit l’en-tête name,amount puis la ligne lunch,8000. Ouvrez le CSV dans un éditeur pour vérifier ces deux lignes ; les caractères \n dans la chaîne Python représentent leurs séparations.

Comprendre la recherche et les limites des contrôles

glob("*.csv") cherche les correspondances dans le dossier visé ; rglob("*.csv") inclut ses sous-dossiers. Un nom se terminant par .csv peut aussi désigner un dossier : si seuls les fichiers sont acceptables, filtrez les correspondances avec is_file(). Utilisez un tri lorsque l’ordre d’affichage doit rester stable plutôt que de dépendre de l’ordre fourni par le système.

Un test exists() indique un état à un moment donné ; le chemin peut changer avant l’ouverture suivante. Il ne supprime ni les problèmes d’accès, ni les erreurs de disque, ni les modifications concurrentes. Une écriture importante demande donc toujours une politique de remplacement et une gestion des erreurs adaptées.

Un chemin relatif ne se rapporte pas automatiquement au script. Si vous lancez le chemin absolu de paths.py depuis un autre dossier, le même code crée lab-data sous ce nouveau dossier de travail. Pour un fichier qui doit être placé à côté du script, le programme peut au contraire construire son chemin à partir de Path(__file__).resolve().parent. Cette décision doit correspondre au contrat voulu.

Avant une écriture ou un nettoyage, affichez ou inspectez le chemin final résolu, par exemple avec path.resolve(). Une résolution ne garantit pas que le fichier existe ni que l’opération soit autorisée ; elle aide à vérifier la destination. Si une erreur de type apparaît à la création de lab-data, vérifiez aussi qu’un fichier ordinaire ne porte pas déjà ce nom.

Comparer les emplacements et restaurer l’exercice

  1. Après le lancement initial, ouvrez lab-data/expenses.csv et vérifiez l’en-tête et le montant 8000. Ce contrôle examine le fichier écrit, au-delà des seuls messages de la console.
  2. Changez uniquement la chaîne "expenses.csv" du programme en "summary.txt". Le premier affichage devient summary.txt .txt summary. Le CSV initial reste présent et le motif *.csv continue de le trouver. Restaurez ensuite le nom expenses.csv.
  3. Créez un second dossier d’exercice vide et ouvrez-y un terminal. Exécutez paths.py par son chemin absolu, en citant ce chemin s’il comporte des espaces. Le nouveau lab-data se trouve sous ce second dossier, tandis que le script est resté dans le premier. Comparez les destinations résolues.
  4. Pour nettoyer, vérifiez les chemins absolus et retirez uniquement les fichiers d’essai identifiés. Ne supprimez pas récursivement un dossier simplement parce que son nom ressemble à celui de l’exercice. Relancez le programme dans le premier dossier si vous souhaitez retrouver le CSV et l’affichage de référence.

Si un chemin vient d’une saisie extérieure, l’opérateur / ne l’enferme pas automatiquement dans votre dossier autorisé. Les chemins absolus, les segments .. et les liens symboliques peuvent changer la destination. Une simple comparaison de préfixes textuels ne suffit pas à prouver l’appartenance à un dossier ; définissez les règles de confinement et les contrôles appropriés avant d’utiliser ces entrées pour modifier des fichiers.