Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Licence CC BY-NC-ND Thierry Parmentelat & Arnaud Legout Inria - UCA

Complément - niveau basique

Outre les objets fichiers créés avec la fonction open, comme on l’a vu dans la vidéo, et qui servent à lire et écrire à un endroit précis, une application a besoin d’un minimum d’utilitaires pour parcourir l’arborescence de répertoires et fichiers, c’est notre propos dans ce complément.

Le module os.path (obsolète)

Avant la version python-3.4, la librairie standard offrait une conjonction d’outils pour ce type de fonctionnalités:

Cet ensemble un peu disparate a été remplacé par une librairie unique pathlib, qui fournit toutes ces fonctionnalités sous un interface unique et moderne, que nous recommandons évidemment d’utiliser pour du nouveau code.

Avant d’aborder pathlib, voici un très bref aperçu de ces trois anciens modules, pour le cas - assez probable - où vous les rencontreriez dans du code existant; tous les noms qui suivent correspondent à des fonctions - par opposition à pathlib qui, comme nous allons le voir, offre une interface orientée objet:

Le module pathlib

C’est la méthode recommandée aujourd’hui pour travailler sur les fichiers et répertoires.

Orienté Objet

Comme on l’a mentionné pathlib offre une interface orientée objet; mais qu’est-ce que ça veut dire au juste ?

Ceci nous donne un prétexte pour une première application pratique des notions de module (que nous avons introduits en fin de semaine 2) et de classe (que nous allons voir en fin de semaine).

De même que le langage nous propose les types builtin int et str, le module pathlib nous expose un type (on dira plutôt une classe) qui s’appelle Path, que nous allons importer comme ceci:

from pathlib import Path

Nous allons faire tourner un petit scénario qui va créer un fichier:

# le nom de notre fichier jouet 
nom = 'fichier-temoin'

Pour commencer, nous allons vérifier si le fichier en question existe.

Pour ça nous créons un objet qui est une instance de la classe Path, comme ceci:

# on crée un objet de la classe Path, associé au nom de fichier
path = Path(nom)

Vous remarquez que c’est cohérent avec par exemple:

# transformer un float en int
i = int(3.5)

en ce sens que le type (int ou Path) se comporte comme une usine pour créer des objets du type en question.

Quoi qu’il en soit, cet objet path offre un certain nombre de méthodes; pour les voir puisque nous sommes dans un notebook, je vous invite dans la cellule suivante à utiliser l’aide en ligne en appuyant sur la touche ‘Tabulation’ après avoir ajouté un . comme si vous alliez envoyer une méthode à cet objet

path.[taper la touche TAB]

et le notebook vous montrera la liste des méthodes disponibles.

# ajouter un . et utilisez la touche <Tabulation>
path
PosixPath('fichier-temoin')

Ainsi par exemple on peut savoir si le fichier existe avec la méthode exists()

# au départ le fichier n'existe pas
path.exists()
False
# si j'écris dedans je le crée
with open(nom, 'w', encoding='utf-8') as output:
    output.write('0123456789\n')
# et maintenant il existe
path.exists()
True

Métadonnées

Voici quelques exemples qui montrent comment accéder aux métadonnées de ce fichier:

# cette méthode retourne (en un seul appel système) les métadonnées agrégées
path.stat()
os.stat_result(st_mode=33188, st_ino=34113446, st_dev=2051, st_nlink=1, st_uid=1001, st_gid=1001, st_size=11, st_atime=1769609136, st_mtime=1769609136, st_ctime=1769609136)

Pour ceux que ça intéresse, l’objet retourné par cette méthode stat est un namedtuple, que l’on va voir très bientôt.

On accède aux différentes informations comme ceci:

# la taille du fichier en octets est de 11 
# car il faut compter un caractère "newline" en fin de ligne 
path.stat().st_size
11
# la date de dernière modification, sous forme d'un nombre
# c'est le nombre de secondes depuis le 1er Janvier 1970
mtime = path.stat().st_mtime
mtime
1769609136.3043182
# que je peux rendre lisible comme ceci
# en anticipant sur le module datetime
from datetime import datetime
mtime_datetime = datetime.fromtimestamp(mtime)
mtime_datetime
datetime.datetime(2026, 1, 28, 14, 5, 36, 304318)
# ou encore, si je formatte pour n'obtenir que
# l'heure et la minute
f"{mtime_datetime:%H:%M}"
'14:05'

Détruire un fichier

# je peux maintenant détruire le fichier
path.unlink()
# ou encore mieux, si je veux détruire 
# seulement dans le cas où il existe je peux aussi faire
try: 
    path.unlink()
except FileNotFoundError:
    print("no need to remove")
no need to remove
# et maintenant il n'existe plus
path.exists()
False
# je peux aussi retrouver le nom du fichier comme ceci
# attention ce n'est pas une méthode mais un attribut 
# c'est pourquoi il n'y a pas de parenthèses
path.name
'fichier-temoin'

Recherche de fichiers

Maintenant je voudrais connaître la liste des fichiers de nom *.json dans le directory data.

La méthode la plus naturelle consiste à créer une instance de Path associée au directory lui-même:

dirpath = Path('./data/')

Sur cet objet la méthode glob nous retourne un itérable qui contient ce qu’on veut:

# tous les fichiers *.json dans le répertoire data/
for json in dirpath.glob("*.json"):
    print(json)
data/marine-e2-abb.json
data/marine-e2-ext.json
data/cities_idf.json
data/cities_world.json
data/marine-e1-ext.json
data/cities_europe.json
data/marine-e1-abb.json
data/cities_france.json

Documentation complète

Voyez la documentation complète ici

Complément - niveau avancé

Pour ceux qui sont déjà familiers avec les classes, j’en profite pour vous faire remarquer le type de notre objet path

type(path)
pathlib.PosixPath

qui n’est pas Path, mais en fait une sous-classe de Path qui est - sur la plateforme du MOOC au moins, qui fonctionne sous linux - un objet de type PosixPath, qui est une sous-classe de Path, comme vous pouvez le voir:

from pathlib import PosixPath
issubclass(PosixPath, Path)
True

Ce qui fait que mécaniquement, path est bien une instance de Path

isinstance(path, Path)
True

ce qui est heureux puisqu’on avait utilisé Path() pour construire l’objet path au départ :)