Modules et importations
- Leçon 8
- 35 min
- Module 3 : Fonctions et structure du programme
Leçon 8 sur 18 · Python pour l'ingénierie de l'IA en pratiqueModules et importations
1. Bases de l'ordinateur et de l'environnement
2. Valeurs et flux de contrôle
3. Fonctions et structure du programme
4. Fichiers, données et services externes
5. Débogage et fiabilité
6. Du carnet Jupyter au projet facile à maintenir
Ce que vous saurez faire
Déplacez les fonctions des billets de soutien dans un paquet nommé ticket_cleaner, puis importez-les dans le script. Deux scripts peuvent alors utiliser les mêmes fonctions. Dans la suite du cours, chaque nouvelle partie aura son propre module.
Carnet JupyterFaites cette leçon dans un carnet Jupyter
Le carnet (notebook) Jupyter contient chaque étape, tâche et vérification de cette leçon, avec les consignes. Ses premières cellules créent le dossier ticket-cleaner tel qu’il est au début de cette leçon. Il fonctionne donc sans votre projet local. Lisez les explications ici et exécutez le code dans le carnet. Aucune installation n’est nécessaire.
Le carnet est en anglais. Colab et Kaggle ouvrent votre propre copie. Il faut un compte Google ou Kaggle gratuit. Vous êtes bloqué ? Consultez le carnet de solution.
Avant de commencerCe qu’il faut savoir et avoir sous la main
Ce que vous devez savoir
- Les fonctions avec un contrat et la fonction
main(), vues dans Le contrat d’une fonction. import sysetimport platform, vus dans Installer et vérifier Python : exemple détaillé.
Ce qu’il vous faut sur votre ordinateur (seulement pour le parcours local; le carnet et les encadrés de cette page n’en ont pas besoin)
count_tickets.pyavec les fonctionsfilter_by_status,count_by_categoryetaverage_priority, ainsi qu’une fonctionmain(). Vous l’avez créé dans Le contrat d’une fonction : exercice guidé. S’il manque ou diffère, remplacez son contenu par l’exemple détaillé. Vous pouvez aussi copier les fichiers de la cellule de préparation du carnet de cette leçon. Elle contient tous les fichiers tels qu’ils sont au début de cette leçon.- Un terminal dans
~/projects/ticket-cleaner. Vous avez créé ce dossier dans Les fichiers et le terminal : exercice guidé. - L’environnement
.venvdu projet, actif dans votre terminal (l’invite commence par(.venv)). Vous l’avez créé dans Isoler les dépendances : exercice guidé. S’il manque ou ne fonctionne plus, supprimez-le et recréez-le à partir du fichier de verrouillage. Suivez Recréer l’environnement à partir de zéro.
Testé avec Python 3.14.6 sur macOS. Le carnet a été testé dans Jupyter.
Un module est un fichier Python
Section intitulée « Un module est un fichier Python »Un module est un fichier de code Python que d’autres parties du code peuvent importer. Chaque fichier .py est un module. Son nom est celui du fichier sans .py : le fichier report.py est le module report.
Vous importez déjà des modules fournis avec Python : import sys, import platform. L’instruction import exécute une fois le fichier du module, puis vous donne accès à ses fonctions et variables. Il existe deux formes :
import platformprint(platform.python_version()) # module name, dot, function name
from platform import python_versionprint(python_version()) # the function name onlyLes deux formes exécutent le même fichier. La première garde le nom du module devant la fonction. Le lecteur voit ainsi d’où vient python_version. La seconde est plus courte. Utilisez la seconde forme pour quelques noms que vous utilisez souvent.
Un paquet est un dossier de modules qui contient un fichier nommé __init__.py. Le fichier __init__.py indique à Python que le dossier est un paquet. Il peut être vide. Vous importez un module d’un paquet avec un point. from ticket_cleaner.report import count_by_category signifie « dans le paquet ticket_cleaner, le module report, la fonction count_by_category ».
La nouvelle organisation
Section intitulée « La nouvelle organisation »À la fin de cette leçon, le projet ressemble à ceci :
ticket-cleaner/├── .venv/├── count_tickets.py ← the script that you run├── requirements.txt├── requirements-lock.txt└── ticket_cleaner/ ← the package: code that other code imports ├── __init__.py └── report.py ← filter_by_status, count_by_category, average_priorityLe nom du dossier du projet contient un - (ticket-cleaner), et celui du paquet contient un _ (ticket_cleaner). C’est volontaire. Le nom d’un module ou d’un paquet doit être un nom Python valide. Le caractère - n’est pas permis dans un nom Python.
Le script garde seulement la partie propre à ce programme : les données et main(). Les fonctions passent dans report.py, car tout programme qui produit des rapports sur les billets peut les utiliser.
Comment Python trouve un module
Section intitulée « Comment Python trouve un module »Quand Python exécute import ticket_cleaner, il le cherche dans une liste de dossiers, dans cet ordre :
- Le dossier du script que vous exécutez. Pour
python count_tickets.py, c’estticket-cleaner/. - Les dossiers des modules de Python, comme
sysetcsv. - Les paquets que vous avez installés dans l’environnement actif, comme
httpx.
Python retient la première correspondance. Cet ordre entraîne deux problèmes. D’abord, le paquet doit se trouver dans le dossier du script que vous exécutez. Vous exécutez donc count_tickets.py, qui se trouve à côté de ticket_cleaner/. Ensuite, un de vos fichiers peut masquer un module Python s’ils portent le même nom. L’erreur fréquente à la fin de cette leçon le montre.
L’importation exécute le fichier
Section intitulée « L’importation exécute le fichier »Une importation exécute chaque ligne du module, une seule fois. Une ligne def définit seulement une fonction. Un module qui contient uniquement des fonctions ne fait donc rien de visible quand vous l’importez. Un module qui contient un print ou un appel au niveau supérieur l’exécute pendant l’importation.
Chaque module possède une variable __name__. Quand vous exécutez un fichier directement, sa variable __name__ vaut "__main__". Quand le fichier est importé, __name__ contient le nom du module. Voici un module qui affiche son nom, exécuté de deux façons :
print("report.py name:", __name__)python ticket_cleaner/report.pypython -c "import ticket_cleaner.report"report.py name: __main__report.py name: ticket_cleaner.reportVous pouvez donc dire « exécutez ceci seulement quand le fichier est le programme, pas quand il est importé » :
if __name__ == "__main__": main()C’est le point d’entrée principal. Placez-le à la fin de chaque script. Un test ou un autre script peut alors importer le fichier pour utiliser ses fonctions, sans exécuter tout le programme.
Exécutez du Python dans votre navigateur
Que vaut __name__ ici?
Cet encadré exécute le code comme programme principal, comme le fait python file.py. Remplacez la condition par __name__ == "report", puis exécutez le code. Pourquoi main() ne s’exécute-t-elle plus?
Tab ajoute quatre espaces. Appuyez sur Esc, puis sur Tab, pour quitter la zone. Ctrl+Enter exécute le code.
Exemple détaillé : diviser le script
Section intitulée « Exemple détaillé : diviser le script »Amira déplace les trois fonctions dans le paquet. Elle ne change pas le code à l’intérieur de chaque fonction.
"""Clean support-ticket records and summarise them."""def filter_by_status(tickets, status="open"): """Return the tickets that have the given status.""" selected = [] for ticket in tickets: if ticket["status"] == status: selected.append(ticket) return selected
def count_by_category(tickets): """Return the number of tickets in each category, sorted by category.""" counts = {} for ticket in tickets: category = ticket["category"] counts[category] = counts.get(category, 0) + 1 return dict(sorted(counts.items()))
def average_priority(tickets): """Return the average priority, or None when there are no tickets.""" if not tickets: return None total = 0 for ticket in tickets: total = total + ticket["priority"] return round(total / len(tickets), 1)Le script commence maintenant par une ligne d’importation et se termine par le point d’entrée principal :
from ticket_cleaner.report import average_priority, count_by_category, filter_by_status
TICKETS = [ {"id": "T-1001", "status": "open", "category": "billing", "priority": 2}, {"id": "T-1002", "status": "closed", "category": "login", "priority": 3}, {"id": "T-1003", "status": "open", "category": "login", "priority": 1}, {"id": "T-1004", "status": "pending", "category": "billing", "priority": 2}, {"id": "T-1005", "status": "open", "category": "billing", "priority": 3}, {"id": "T-1006", "status": "closed", "category": "shipping", "priority": 1},]
def main(): status = "open" selected = filter_by_status(TICKETS, status) print(f"Tickets with status '{status}': {len(selected)}") if not selected: print("No tickets to count.") return for category, count in count_by_category(selected).items(): print(f" {category}: {count}") print(f"Average priority: {average_priority(selected)}")
if __name__ == "__main__": main()La sortie reste la même. C’est le test d’un remaniement : la structure a changé, mais pas le comportement.
Exercice guidé : créer le paquet
Section intitulée « Exercice guidé : créer le paquet »-
Dans le dossier
ticket-cleaner, créez le dossier du paquet :Fenêtre de terminal mkdir ticket_cleaner -
Dans VS Code, créez
ticket_cleaner/__init__.pyavec la seule ligne de chaîne de documentation de l’exemple détaillé. -
Créez
ticket_cleaner/report.py. Déplacez-y les trois fonctions decount_tickets.py(coupez-les, puis collez-les). -
Dans
count_tickets.py, ajoutez la ligne d’importation au début. Remplacez la dernière ligne,main(), par le point d’entrée principal. -
Exécutez le script :
Fenêtre de terminal python count_tickets.pySortie Tickets with status 'open': 3billing: 2login: 1Average priority: 2.0 -
Affichez le contenu du dossier du paquet :
ls ticket_cleaner. Vous voyez un nouveau dossier,__pycache__. Python y enregistre une copie compilée de chaque module importé pour accélérer la prochaine importation. Vous ne le modifiez pas. Si vous utilisez Git, ajoutez__pycache__/à.gitignore.
À vous de jouer : un deuxième script
Section intitulée « À vous de jouer : un deuxième script »La personne responsable du soutien veut un court rapport de tous les billets urgents, peu importe leur statut. Créez un nouveau script, urgent_report.py, dans le dossier du projet. Il doit :
- Importer
filter_by_statusdu paquet. Ne copiez pas la fonction. - Utiliser les six mêmes billets.
- Pour chaque statut (
"open"(ouvert),"pending"(en attente),"closed"(fermé)), afficher le statut et le nombre de billets de priorité1. - Se terminer par le point d’entrée principal.
open: 1 urgentpending: 0 urgentclosed: 1 urgentAfficher une réponse
from ticket_cleaner.report import filter_by_status
TICKETS = [ # the same six tickets as in count_tickets.py]
def main(): for status in ["open", "pending", "closed"]: selected = filter_by_status(TICKETS, status) urgent = [ticket for ticket in selected if ticket["priority"] == 1] print(f"{status}: {len(urgent)} urgent")
if __name__ == "__main__": main()Les six billets se trouvent maintenant dans deux scripts. C’est aussi une copie. Dans le module 4, les deux scripts liront plutôt les billets dans un seul fichier de données.
Erreur courante
Un nom de fichier qui masque un module Python
Symptôme : du code qui fonctionnait s’arrête avec une erreur concernant un module fourni avec Python. Par exemple, vous avez créé un fichier nommé csv.py pour vous exercer :
AttributeError: module 'csv' has no attribute 'DictReader' (consider renaming '/Users/amira/projects/ticket-cleaner/csv.py' since it has the same name as the standard library module named 'csv' and prevents importing that standard library module)Cause : Python cherche d’abord les modules dans le dossier de votre script. Votre fichier csv.py porte le même nom que le module csv de Python. Donc, import csv trouve votre fichier à la place. Votre fichier ne contient pas DictReader. Les noms qui causent souvent ce problème sont csv.py, json.py, random.py, test.py, email.py et ceux des paquets installés, comme httpx.py.
Solution :
- Renommez votre fichier pour décrire votre code, par exemple
read_tickets.py. - Supprimez le dossier
__pycache__à côté du fichier pour qu’aucune copie compilée de l’ancien fichier ne reste. - Exécutez le programme de nouveau.
Vérifiez votre compréhension
Vous importez un module, et le terminal affiche un rapport que vous n'avez pas demandé. Que manque-t-il dans ce module, et où?
Afficher la réponse
Le module appelle son code au niveau supérieur, donc l’importation l’exécute. Placez l’appel dans if __name__ == "__main__": à la fin du fichier. Le code s’exécute alors seulement quand vous lancez le fichier directement, pas quand un autre fichier l’importe.
Votre réponse contient-elle les points principaux de la nôtre ?
Connectez-vous et inscrivez-vous au cours pour enregistrer vos réponses. Chaque vérification compte pour le certificat.
Vérifiez votre compréhension
Pourquoi le paquet s'appelle-t-il ticket_cleaner et non ticket-cleaner, comme le dossier du projet?
Afficher la réponse
import ticket-cleaner n’est pas du Python valide, car Python interprète - comme un signe de soustraction. Le nom d’un module ou d’un paquet doit être un nom Python valide : lettres, chiffres et _, sans chiffre au début. Le dossier du projet n’est jamais importé, donc son nom peut contenir un -.
Votre réponse contient-elle les points principaux de la nôtre ?
Connectez-vous et inscrivez-vous au cours pour enregistrer vos réponses. Chaque vérification compte pour le certificat.
Récapitulatif
- Un module est un fichier
.py. Un paquet est un dossier de modules qui contient un fichier__init__.py. import moduleetfrom module import nameexécutent tous deux le module une fois. Python cherche d’abord dans le dossier du script, puis dans les modules Python, puis dans les paquets installés.- Ne donnez pas à vos fichiers les mêmes noms que les modules Python ou les paquets installés.
- Terminez chaque script par
if __name__ == "__main__": main()pour qu’une importation ne l’exécute pas. - Exécutez les scripts depuis le dossier du projet. Utilisez
python -m package.modulepour un module dans un paquet.
Ensuite, vous donnerez à chaque billet un type adapté avec une classe de données. Vous ajouterez aussi des annotations de type qui montrent le contrat de chaque fonction sur sa ligne def.
Leçon suivante : Les enregistrements structurés