Les modules et les imports
Ce que ce chapitre apporte 5 points
- Comprendre ce qu'est un module, et ce qu'un import exécute réellement.
- Savoir où Python cherche un module, et pourquoi l'ordre de recherche compte.
- Importer de cinq façons, et savoir laquelle éviter.
- Créer ses propres modules, puis les ranger en paquets.
- Distinguer la bibliothèque standard des paquets installés, et déclarer ses dépendances.
Un module est un fichier, un import le rend disponible, et le découpage en modules est ce qui rend un programme relisible. Un programme qui grandit dans un seul fichier devient vite illisible : des centaines de lignes, des fonctions partout, impossible de s'y retrouver. La solution des développeurs professionnels : découper le code en modules, des fichiers séparés qui ont chacun un rôle clair, et qu'on réutilise à volonté.
Ce chapitre part des modules tout faits, dont Python fournit des centaines, puis passe à ceux qu'on écrit soi-même et à l'organisation d'un projet.
Qu'est-ce qu'un module ?
Définition : Un module est un fichier Python (
.py) contenant du code (fonctions, variables, classes…) qu'on peut importer dans d'autres scripts pour le réutiliser. Les classes, qui regroupent des données et les fonctions qui les concernent, sont présentées au chapitre sur les classes et les objets.
Fichier maths_utils.py :
def carre(x):
return x * x
Fichier programme.py :
import maths_utils
print(maths_utils.carre(5)) # 25
main.py, et le navigateur n'a pas de disque où déposer maths_utils.py à côté. Pour l'essayer, il faut créer les deux fichiers dans le même dossier sur l'ordinateur, puis lancer programme.py.Les blocs des sections suivantes, eux, importent des modules de la bibliothèque standard : ceux-là s'exécutent ici même.
import math puis import math une seconde fois : que se passe-t-il ?
Ce qu'un import charge vraiment
Un import n'est pas une déclaration décorative en tête de fichier : c'est une instruction qui s'exécute, et qui range le contenu du module dans un objet portant son nom.
import math ne verse pas le contenu de math dans le programme : il pose sur le bureau une commode nommée math, tiroirs fermés. Pour s'en servir, on ouvre le bon tiroir avec un point : math.sqrt(25).
Le contenu de cette commode se consulte : dir() liste les noms qu'un module met à disposition.
Le bloc suivant est faux exprès : il oublie d'ouvrir le tiroir.
NameError: name 'sqrt' is not defined. L'import a bien réussi : math existe, mais sqrt n'existe que dedans. La correction tient au préfixe : math.sqrt(25).
1.Quelle différence entre import math et from math import sqrt ?
2.Pourquoi éviter from module import * ?
Où Python va chercher un module
import outils ne dit pas où se trouve outils. Python le cherche, dans un ordre fixe, et s'arrête au premier fichier trouvé. Cet ordre est une liste, visible depuis le programme :
La liste commence toujours par le dossier du fichier lancé, puis vient la bibliothèque standard, puis les paquets installés. Trois conséquences pratiques en découlent :
| Situation | Ce qui se passe |
|---|---|
Un fichier random.py dans le dossier | il est trouvé avant le vrai module random |
| Un module absent de la liste | ModuleNotFoundError, même si le fichier existe ailleurs sur le disque |
| Deux modules de même nom | le premier de la liste gagne, sans avertissement |
La première ligne explique l'erreur la plus déroutante du débutant, et l'encadré plus bas la décrit. Le mécanisme n'a rien de mystérieux : ce n'est qu'une liste parcourue dans l'ordre.
Ce que l'import exécute
Un import ne copie pas du texte : il exécute le fichier, de haut en bas, une seule fois. Tout ce qui s'y trouve au niveau du fichier, en dehors des def, tourne à ce moment-là.
C'est ce cache qui rend le second import gratuit, et c'est lui aussi qui fait que modifier un module déjà importé n'a aucun effet tant que l'interpréteur tourne. Dans un carnet Jupyter, où l'interpréteur survit à l'édition, c'est la cause d'une heure perdue à corriger un fichier dont la version chargée ne change pas.
C'est enfin la raison d'être du bloc if __name__ == "__main__": : sans lui, importer un module pour y prendre une fonction exécuterait aussi ses lignes de démonstration.
Les façons d'importer
Python offre plusieurs syntaxes selon ce dont on a besoin. Ces exemples utilisent des modules standards (déjà installés) : on peut donc les exécuter ici même.
Importer tout le module :
Importer un seul élément :
Renommer avec as :
Importer plusieurs éléments :
from math import *math. devant chaque appel. C'est précisément le problème.On renverse le tiroir sur le bureau sans regarder ce qui en sort. Si on avait une variable nommée
pi, e ou pow, elle est écrasée sans le moindre avertissement. Et à la lecture, plus rien ne dit d'où vient gamma : de ce module, d'un autre, ou du code.Écrire
import math et préfixer, ou from math import sqrt, pi en nommant ce qu'on prend. Le préfixe n'est pas une lourdeur, c'est une information.
À quoi sert le bloc if __name__ == "__main__": ?
Les modules standards les plus utiles
Python est « livré piles incluses » : des centaines de modules prêts à l'emploi.
| Module | Utilisation | Exemple |
|---|---|---|
math | Fonctions mathématiques | math.sqrt(16) |
random | Nombres aléatoires | random.randint(1, 6) |
datetime | Dates et heures | datetime.date.today() |
os | Fichiers, dossiers, système | os.listdir() |
sys | Paramètres du programme | sys.argv |
La liste complète est dans la documentation officielle.
Créer ses propres modules
On peut répartir le code dans plusieurs fichiers pour le rendre plus lisible.
Fichier outils.py :
def saluer(nom):
print(f"Bonjour {nom} !")
def aire_carre(cote):
return cote ** 2
Fichier main.py :
import outils
outils.saluer("Alice")
print("Aire :", outils.aire_carre(5))
random.py dans le dossier sera trouvé avant le vrai module random de Python. Son propre fichier s'importe alors lui-même, et l'erreur qui en découle, du type module 'random' has no attribute 'randint', ne dit pas un mot du vrai coupable.La règle vaut aussi pour
math.py, os.py, json.py, email.py. Devant une erreur d'import incompréhensible, le nom de ses propres fichiers est la première chose à vérifier.
Organiser un projet
La règle tient en une phrase : un fichier par rôle, et un point d'entrée unique.
mon_projetmain.pyle programme : il appelle, il n'implémente pasoutils.pyles fonctions réutilisablesmain.py importe outils et enchaîne les appels. outils.py ne sait pas qu'il existe un main.py et ne l'importe jamais : la dépendance va dans un seul sens, sinon les deux fichiers s'importent l'un l'autre et Python s'y perd.
Quand outils.py devient trop gros, on le coupe en plusieurs fichiers rangés dans un dossier, et l'import prend un point de plus : from calculs.statistiques import moyenne. Le parcours Outils de développement traite en détail de la structure d'un projet, des dépendances et des environnements.
__name__ la valeur "__main__". Quand ce même fichier est importé par un autre, __name__ contient son nom de module.
C'est ce qui explique la ligne if name == "main": qu'on croisera dans presque tous les programmes Python. Elle protège le code de démonstration d'un fichier : il s'exécute quand on lance le fichier, et reste silencieux quand on l'importe pour ses fonctions.
La formule ne sert vraiment que le jour où l'on écrit un fichier destiné à être importé, mais elle se croise partout bien avant.
Quand un dossier devient un module : les paquets
Un fichier unique finit par gonfler. Le découpage suivant consiste à ranger plusieurs modules dans un dossier, qui devient lui-même importable : c'est un paquet.
mon_projetmain.pyle point d'entréecalculsle paquet__init__.pymarque le dossier comme paquet, souvent videstatistiques.pymoyenne, écart-typegeometrie.pyaires, périmètresdonneesun second paquet, autre rôle__init__.pylecture.pyL'import suit alors le chemin, un point par niveau :
from calculs.statistiques import moyenne
from donnees.lecture import charger_csv
import calculs.geometrie as geo
print(geo.aire_cercle(3))
Le fichier __init__.py peut rester vide : sa seule présence suffit à déclarer le dossier comme paquet. Quand il contient quelque chose, c'est en général une poignée d'imports qui raccourcissent l'écriture pour celui qui se sert du paquet, de sorte que from calculs import moyenne fonctionne sans connaître le découpage interne.
La dépendance va dans un seul sens.
main.pyimportecalculs, etcalculsn'importe jamaismain. Si deux modules s'importent l'un l'autre, le premier chargé s'interrompt au milieu pour charger le second, lequel réclame un nom que le premier n'a pas encore défini. L'erreur,cannot import name ... (most likely due to a circular import), désigne le symptôme et pas la cause. La sortie consiste presque toujours à extraire dans un troisième module ce dont les deux ont besoin.
Deux modules qui s'importent mutuellement produisent quoi ?
Au-delà de la bibliothèque standard
Les modules vus jusqu'ici arrivent avec Python. Des dizaines de milliers d'autres se téléchargent, et c'est là que se trouvent les outils du métier :
| Paquet | Ce qu'il apporte |
|---|---|
numpy | calcul sur des tableaux de nombres |
matplotlib | courbes et figures |
pandas | tableaux de données, comme un tableur programmable |
requests | interroger un site ou une interface web |
openpyxl | lire et écrire des fichiers Excel |
L'installation passe par pip, depuis le terminal et non depuis le programme :
pip install numpy pandas
Une fois installé, le paquet s'importe comme n'importe quel module. La différence de statut est invisible dans le code, et c'est précisément ce qui piège : un programme qui fonctionne sur une machine échoue sur une autre par ModuleNotFoundError, non parce que le code diffère, mais parce que l'installation diffère.
C'est pourquoi un projet déclare ses dépendances dans un fichier, requirements.txt, et les installe dans un environnement qui lui est propre. Le parcours Outils de développement traite ces deux points, qui deviennent indispensables dès qu'un programme quitte la machine où il est né.
Mettre en pratique
Exercice : le lancer de dés. À l'aide du module random, simuler le lancer de deux dés à six faces, puis afficher les deux résultats et leur somme.
Afficher la solution
random.randint(1, 6) tire un entier entre 1 et 6 inclus, la borne haute comprise, ce qui n'est pas le cas de range(1, 6).
Relancer plusieurs fois : sur cette page, le tirage ne change pas. L'éditeur fixe la graine du générateur avant chaque exécution, pour que la correction d'un exercice ne dépende jamais de la chance. Sur une machine, le même programme donne deux dés différents à chaque lancement. Et l'inverse s'y obtient aussi : random.seed(0) en tête de fichier fige le hasard à volonté, ce qui est la façon habituelle de rendre un tirage reproductible.
Chapitre révisé en octobre 2026 · Une erreur dans ce chapitre ?
Dans la bibliothèque d'exercices
Importer ce dont on a besoin, savoir sous quel nom on l'appelle, et ce qui s'exécute à l'import.
- Le nom sous lequel on importe2 · Fonctions
- Importer ce dont on a besoin2 · Fonctions
- Ce qui s'exécute à l'import3 · Confirmé