3.1Modules, packages & bibliothèque standard
L'essentiel en 30 secondes
- Un module = un fichier .py, un package = un dossier de modules : on réutilise via import au lieu de copier-coller — from stats import frequence, alias import x as y.
- La bibliothèque standard est le coffre déjà payé : pathlib, datetime, collections, itertools, argparse, sqlite3 — testé, documenté, sans dépendance à installer.
- Le bloc __main__ sépare usage importé et usage direct : la démo ne tourne qu'en exécution directe, jamais à l'import — fini les effets de bord.
Mini-cas filé — Nabil range ses scripts d'analyse
Nabil, data analyst junior à Alger, analyse les ventes avec trois scripts qui se copient les mêmes fonctions de nettoyage : une correction à Alger-centre, oubliée dans la copie Oran, fausse un rapport. Il range le commun dans un module stats.py (fonction frequence avec Counter), importe via from stats import frequence, protège la démo par if __name__ == "__main__", et remplace son bricolage de dates par datetime et pathlib de la standard. Un seul code, trois analyses justes.
Ce même cas revient dans le cours, le schéma, le script et le défi 48h.
1. Modules, packages et imports propres
Quand le projet grandit, tout mettre dans un seul fichier devient ingérable : un module est un fichier .py réutilisable (import stats puis stats.frequence()), un package est un dossier regroupant des modules cohérents. On importe en tête de fichier, groupés (standard → tiers → locaux), en absolu (from monapp import stats), avec les variantes import math, from math import sqrt, import x as y — et jamais from x import * qui pollue l'espace de noms.
Le bloc if __name__ == "__main__": rend un fichier à la fois exécutable et importable : le code sous ce bloc ne tourne QUE lancé directement (python stats.py), pas à l'import. Nabil y place sa démo sur un échantillon de ventes d'Alger : importé, le module ne fournit que des fonctions ; exécuté, il montre l'exemple. Les imports circulaires (A importe B qui importe A) signalent un découpage à revoir, pas un tour à forcer.
2. La bibliothèque standard : vérifier avant d'installer
Python est livré avec les piles : pathlib (chemins modernes), datetime (dates et heures), collections (Counter, defaultdict), itertools (itérations), argparse (interfaces en ligne de commande), sqlite3 (base embarquée), sans oublier os, sys, json, random, math. Avant tout pip install, Nabil vérifie le coffre standard : compter les ventes par ville avec Counter, lister un dossier avec pathlib, dater un export avec datetime.
Réflexe professionnel : standard d'abord, PyPI ensuite. La standard est testée, documentée et sans dépendance — chaque bibliothèque externe ajoute un coût (installation, versions, maintenance). Nabil ne sort pip que pour ce que la standard ne couvre pas (analyse tabulaire, graphiques du niveau 4), et garde ses imports absolus et groupés pour rester lisible.
🔎 Exemple concret — Stats des ventes en module protégé
Nabil compte les ventes par ville depuis un module réutilisable.
from collections import Counter
def frequence(contacts):
return Counter(c["ville"] for c in contacts)
if __name__ == "__main__":
echantillon = [{"ville": "Alger"}, {"ville": "Oran"}, {"ville": "Alger"}]
print(frequence(echantillon))
Lecture : importé = fonctions seules ; exécuté directement = démo sur l'échantillon.
Leçon : le bloc __main__ protège des effets de bord à l'import.
Vocabulaire de la section
- Module
- Un fichier .py réutilisable : on y accède avec import mon_module, puis mon_module.fonction().
Exemple simple : Le stats.py de Nabil importé par ses trois analyses.
Ce que ce n'est pas : un copier-coller de la fonction dans chaque script.
Réflexe : ranger le commun dans un module dès la 2e copie.
- Package
- Un dossier regroupant des modules cohérents pour structurer un projet.
Exemple simple : Un dossier monapp/ avec stats.py et nettoyage.py.
Ce que ce n'est pas : vingt fichiers .py en vrac sans dossier.
Réflexe : regrouper par thème, importer en absolu.
- import / from / as
- Charge du code réutilisable : import math, from math import sqrt, import x as y ; jamais from x import *.
Exemple simple : from stats import frequence chez Nabil.
Ce que ce n'est pas : from stats import * qui pollue le namespace.
Réflexe : importer explicite, en tête, groupé.
- Bibliothèque standard
- Modules fournis d'office avec Python : datetime, pathlib, collections, itertools, argparse, sqlite3, os, json, random, math…
Exemple simple : Counter pour les villes, datetime pour dater l'export de Nabil.
Ce que ce n'est pas : installer un paquet externe pour ce que Counter fait déjà.
Réflexe : vérifier la standard avant pip install.
- if __name__ == "__main__"
- Bloc exécuté seulement en lancement direct, pas à l'import : sépare la démo des fonctions.
Exemple simple : La démo sur l'échantillon de Nabil, muette à l'import.
Ce que ce n'est pas : un print de test qui se rejoue à chaque import.
Réflexe : __main__ systématique pour toute démo.
En pratique — Organiser en modules et exploiter la stdlib
- Créez un module « stats.py » avec deux fonctions (ex. frequence, moyenne), puis importez-le dans un autre fichier et appelez ses fonctions.
- Explorez la stdlib : datetime.now() pour dater un export, Counter pour compter des villes, pathlib pour lister un dossier.
- Utilisez « from module import fonction » et l'alias « import x as y » : comparez la lisibilité des deux styles.
- Ajoutez un bloc « if __name__ == '__main__' » avec une démo : vérifiez qu'elle ne s'exécute pas à l'import.
Script prêt à dire — présenter son module (30 s)
« Le commun vit dans stats.py : fonction frequence avec Counter, importée par from stats import frequence, démo protégée sous __main__. Dates et chemins via datetime et pathlib de la standard, imports absolus en tête, jamais d'étoile. Un seul code pour trois analyses. »
À dire en revue ; montrer l'import et le bloc __main__.
Modèle copier-coller — module + import protégé
from collections import Counter
from datetime import datetime
from pathlib import Path
def frequence(contacts):
return Counter(c["ville"] for c in contacts)
def dater_export():
return datetime.now().strftime("%Y-%m-%d")
if __name__ == "__main__":
print(frequence([{"ville": "Alger"}]))
print(sorted(Path(".").iterdir()))
Indépendant
Un module stats.py avec Counter suffit à fiabiliser les rapports mensuels.
PME à Alger
Nabil partage son module entre les analyses Alger-centre et Oran sans recopier.
Équipe produit
Imposer imports absolus groupés et __main__ systématique pour des modules importables.
Débutant
Cette semaine : un module, deux fonctions, une démo sous __main__.
✓ Bonnes pratiques
- Placer un bloc __main__ systématique pour toute démo ou test manuel.
- Vérifier la bibliothèque standard avant d'installer quoi que ce soit.
- Importer en absolu, groupé (standard → tiers → locaux), jamais avec *.
✗ Pièges fréquents
- Copier-coller une fonction entre fichiers au lieu d'en faire un module.
- Utiliser from x import * (noms écrasés, origine illisible).
- Bricoler des imports circulaires au lieu de redécouper les modules.
Points clés à retenir
- MODULE = un fichier .py ; PACKAGE = un dossier de modules : on importe (from/as) au lieu de recopier.
- La BIBLIOTHÈQUE STANDARD couvre dates, chemins, comptages, CLI, base embarquée… SANS rien installer.
- if __name__ == '__main__' sépare le code EXÉCUTABLE (démo) du code IMPORTABLE (fonctions).
- Imports PROPRES : en tête, groupés, ABSOLUS, jamais d'étoile ; circulaires = découpage à revoir.
Défi 48h — appliquez demain
Extrayez 1 fonction dupliquée dans un module importé par 2 scripts, avec démo sous __main__.
- Je distingue module (fichier) et package (dossier).
- Mes imports sont absolus, groupés, sans étoile.
- Ma démo sous __main__ ne tourne plus à l'import.
Questions fréquentes
Quelle différence entre « import math » et « from math import sqrt » ?
import math charge tout le module, à appeler avec math.sqrt() (origine explicite). from math import sqrt n'importe que sqrt, appelable directement. La première forme se lit mieux en équipe ; évitez from module import * qui pollue l'espace de noms et masque les collisions.
À quoi sert vraiment « if __name__ == '__main__' » ?
À rendre un fichier à la fois exécutable et importable : le code sous ce bloc ne tourne QUE lancé directement (python fichier.py), pas à l'import. On y met la démo ou le point d'entrée — importé, le module ne fournit que des fonctions, sans effet de bord.
Que se passe-t-il avec le bloc if __name__ == "__main__" à l'import ?