Adloun

Fichiers, exceptions et modules

Cours · Python (école d'ingénieur), chapitre 7 · école d'ingénieur, informatique · le début du chapitre, la suite sur Adloun

7.1 Introduction et Motivation

Pour interagir avec le monde extérieur, un programme doit lire et écrire des fichiers (sauvegardes, données physiques, journaux de log). Cependant, les opérations d'entrées/sorties sont sujettes à des erreurs imprévisibles (fichier manquant, permission refusée, disque plein). Il est donc indispensable d'adopter des structures robustes pour gérer l'ouverture des ressources (gestionnaires de contexte) et la capture des anomalies (exceptions). De plus, la modularité du code passe par la création et l'importation de modules, permettant de structurer proprement des projets de grande envergure. Enfin, ce chapitre aborde les aspects pratiques de l'encodage des caractères (ASCII, Latin-1, Unicode/UTF-8), du traitement de fichiers de données structurées (CSV) et d'images numériques.

7.2 Interaction avec le Système d'Exploitation

Le module standard os permet à Python de dialoguer directement avec le système d'exploitation pour manipuler des répertoires et des fichiers.

7.2.1 Le module os

Définition 7.1Répertoire de travail et Navigation

Les fonctions principales pour gérer le système de fichiers sont :

  • os.getcwd() : renvoie le chemin absolu du répertoire courant (working directory).
  • os.chdir(chemin) : change le répertoire courant vers le chemin spécifié.
  • os.listdir(chemin) : renvoie la liste des noms des fichiers et dossiers contenus dans le répertoire désigné.
  • os.walk(chemin) : parcourt récursivement une arborescence (générateur de tuples (racine, dossiers, fichiers)).
Exemple 7.2Navigation de base

import os

# Affichage du répertoire courant
print("Répertoire actuel :", os.getcwd())

# Liste des fichiers du dossier courant
print("Contenu :", os.listdir("."))

# Parcours récursif d'une arborescence
for racine, dossiers, fichiers in os.walk("."):
    for fichier in fichiers:
        if fichier.endswith(".py"):
            print(f"Fichier Python trouvé : {os.path.join(racine, fichier)}")

7.2.2 Le module pathlib (approche moderne)

Depuis Python 3.4, le module pathlib propose une approche orientée objet pour manipuler les chemins de fichiers, plus lisible et plus robuste que os.path.

Exemple 7.3pathlib en action

from pathlib import Path

# Création d'un chemin
chemin = Path("dossier") / "sous_dossier" / "fichier.txt"

# Vérification d'existence
if chemin.exists():
    print("Le fichier existe")

# Lecture simplifiée
contenu = chemin.read_text(encoding="utf-8")

# Écriture simplifiée
chemin.write_text("Nouveau contenu", encoding="utf-8")

# Parcours d'un dossier
for p in Path(".").glob("*.py"):
    print(f"Fichier Python : {p.name}")

7.3 Lecture et Écriture de Fichiers

7.3.1 Modes d'Ouverture et Gestionnaires de Contexte

La fonction native open() permet de créer un flux entre le programme et un fichier physique sur le disque. Elle prend deux arguments principaux : le chemin du fichier et le mode d'ouverture.

ModeDescription
'r'Lecture seule (défaut). Le fichier doit exister.
'w'Écriture (écrase le fichier s'il existe, le crée sinon).
'a'Ajout (append) à la fin du fichier.
'x'Création exclusive (erreur si le fichier existe déjà).
'rb'Lecture binaire (images, fichiers non textuels).
'wb'Écriture binaire.
Figure : Modes d'ouverture des fichiers
Définition 7.4Gestionnaire de contexte with

Pour garantir la fermeture automatique d'un fichier même si une erreur survient, on utilise le mot-clé with. Le fichier est proprement refermé dès la sortie du bloc indenté.

7.3.2 Méthodes de Lecture

Exemple 7.5Parcours ligne par ligne - version mémoire efficace

with open("exemple.txt", "r", encoding="utf-8") as f:
    for num, ligne in enumerate(f, start=1):
        print(f"Ligne {num} : {ligne.rstrip()}")  # rstrip() enlève le \n final

7.3.3 Méthodes d'Écriture

Exemple 7.6Écriture dans un fichier

# Écriture avec écrasement
with open("sortie.txt", "w", encoding="utf-8") as f:
    f.write("Première ligne\n")
    f.write("Deuxième ligne\n")

# Ajout à la fin du fichier
with open("sortie.txt", "a", encoding="utf-8") as f:
    f.write("Troisième ligne (ajoutée)\n")

7.4 Fichiers CSV (Comma-Separated Values)

Le format CSV est couramment utilisé pour stocker des tableaux de données. Chaque ligne représente une ligne de tableau, et les colonnes sont délimitées par un caractère (virgule, point-virgule, tabulation).

7.4.1 Lecture naïve avec split()

Exemple 7.7Lecture de planètes avec conversion de types

Supposons un fichier planetes.csv contenant :


Mercure,2439,3.7,88
Vénus,6052,8.9,225
Terre,6378,9.8,365
Mars,3396,3.7,687

Le script suivant lit ce fichier, sépare les colonnes avec la méthode split() et convertit les types :


tab = []
with open("planetes.csv", "r", encoding="utf-8") as f:
    for ligne in f:
        colonnes = ligne.strip().split(",")
        nom = colonnes[0]
        rayon = int(colonnes[1])
        gravite = float(colonnes[2])
        periode = int(colonnes[3])
        tab.append([nom, rayon, gravite, periode])

print(tab)

7.4.2 Le module csv (gestion robuste)

Le module standard csv gère correctement les cas complexes (virgules dans les champs, guillemets, etc.).

Exemple 7.8Utilisation du module csv

import csv

# Lecture
with open("planetes.csv", "r", encoding="utf-8") as f:
    reader = csv.reader(f, delimiter=',')
    for ligne in reader:
        print(ligne)  # ligne est une liste de chaînes

# Écriture
with open("sortie.csv", "w", encoding="utf-8", newline='') as f:
    writer = csv.writer(f, delimiter=';')
    writer.writerow(["Nom", "Rayon", "Gravité", "Période"])
    writer.writerow(["Terre", 6378, 9.8, 365])

7.5 Encodage des Caractères

7.5.1 Le jeu de caractères ASCII

À l'origine, le codage ASCII représentait les caractères sur 7 bits (128 caractères possibles). Il comprend les lettres capitales et minuscules anglaises, les chiffres, la ponctuation et des caractères de contrôle. En Python, ord() renvoie le code numérique d'un caractère et chr() renvoie le caractère correspondant :


>>> ord('A')
65
>>> chr(97)
'a'

7.5.2 De Latin-1 à Unicode / UTF-8

La norme ISO-8859-1 (Latin-1) utilise le 8e bit pour ajouter 128 caractères (accents européens). Cependant, Latin-1 est limité aux alphabets européens.

Définition 7.9Unicode et UTF-8

Unicode attribue un identifiant numérique unique à chaque caractère de toutes les langues du monde. L'encodage UTF-8 (défaut en Python) stocke ces identifiants sur 1 à 4 octets, tout en conservant une parfaite compatibilité avec l'ASCII (les caractères ASCII sont codés sur un seul octet, identique à leur codage historique).

iRemarqueErreurs de décodage

Si un fichier UTF-8 est ouvert avec un mauvais encodage, des caractères étranges apparaissent ou une exception est levée.


# Bonne pratique : spécifier explicitement l'encodage
with open("fichier.txt", "r", encoding="utf-8") as f:
    contenu = f.read()

# Gestion des erreurs d'encodage
with open("fichier.txt", "r", encoding="utf-8", errors="ignore") as f:
    contenu = f.read()  # ignore les caractères non décodables

7.6 Gestion des Exceptions

Les exceptions sont des signaux émis par Python pour indiquer la survenue d'une erreur (division par zéro, fichier introuvable, type incorrect).

7.6.1 Hiérarchie des Exceptions

7.6.2 Bloc try-except-else-finally

Définition 7.10Structure complète

try:
    # Code susceptible de lever une exception
    valeur = int(input("Entrez un nombre : "))
except ValueError:
    # Exécuté si une ValueError est levée
    print("Ce n'est pas un nombre valide.")
except ZeroDivisionError:
    # Exécuté si une ZeroDivisionError est levée
    print("Division par zéro.")
else:
    # Exécuté si aucune exception n'a été levée
    print(f"Valeur saisie : {valeur}")
finally:
    # Toujours exécuté (quoi qu'il arrive)
    print("Fin du traitement.")

7.6.3 Lever des exceptions avec raise

Exemple 7.11Validation de données

def racine_carree(x):
    if x < 0:
        raise ValueError("La racine carrée n'est pas définie pour les négatifs")
    return x ** 0.5

try:
    print(racine_carree(-1))
except ValueError as e:
    print(f"Erreur : {e}")

7.7 Modules et Packages

7.7.1 Import de modules

Python dispose d'une riche bibliothèque standard. On peut également créer ses propres modules.


# Import simple
import math
print(math.sqrt(2))

# Import avec alias
import numpy as np

# Import sélectif
from os import getcwd, listdir
print(getcwd())

# Import de tout (déconseillé)
from math import *

7.7.2 Création d'un module

Un module Python est simplement un fichier .py. Par exemple, le fichier mon_module.py :


# mon_module.py
def dire_bonjour(nom):
    return f"Bonjour, {nom} !"

PI = 3.14159

if __name__ == "__main__":
    # Code exécuté uniquement si le fichier est lancé directement
    print("Test du module :", dire_bonjour("Monde"))

Utilisation dans un autre script :


import mon_module

print(mon_module.dire_bonjour("Alice"))
print(mon_module.PI)

7.7.3 La condition if __name__ == "__main__"

Cette construction permet de distinguer l'exécution directe d'un script de son import en tant que module. Elle est essentielle pour :

7.7.4 Organisation en packages

Un package est un dossier contenant un fichier __init__.py (qui peut être vide) et des modules.


mon_package/
|-- __init__.py
|-- module1.py
+-- module2.py

Import depuis un package :


from mon_package import module1
from mon_package.module2 import ma_fonction

7.8 Traitement Numérique d'Images (Approfondissement)

Note : Cette section est optionnelle et suppose l'installation de NumPy et Matplotlib.

7.8.1 Modélisation matricielle

Une image numérique est modélisée par une grille bidimensionnelle de pixels.

La suite du cours est sur Adloun

Le chapitre en entier, formules et figures comprises, avec le tuteur, les fiches, les QCM et les exercices.

Lire la suite du cours

En accès libre, sans inscription.

Exercices corrigés de ce chapitre

Lire la suite du cours →