Terminale · Langages et programmation

Modules, bibliothèques, API et documentation

Pour utiliser une fonction de tri, vous n’avez pas besoin de relire chaque ligne de son implémentation. Vous devez en revanche savoir ce qu’elle reçoit, ce qu’elle produit et si elle modifie vos données. La modularité rend cette séparation explicite et permet de construire des programmes compréhensibles à plusieurs.

SofienAvec SofienIngénieur et enseignant en informatique
Dans ce chapitre

Un cap pour ce chapitre

Ce que vous saurez faire

  • Séparer interface et implémentation.
  • Lire un contrat d’API.
  • Créer et documenter un module simple.
Les bases utiles pour commencer

Donner une responsabilité à chaque module

Un module Python est notamment un fichier qui regroupe des définitions utiles. On peut séparer la lecture de données, les calculs et leur présentation. Chaque partie reçoit des informations par une interface explicite. Cette séparation permet de tester les calculs sans lancer une interface graphique ni lire un vrai fichier à chaque essai.

Le découpage doit suivre des responsabilités cohérentes. Créer un fichier pour chaque ligne n’améliore pas la compréhension. À l’inverse, un module qui lit, calcule, affiche et modifie des variables globales rend les dépendances difficiles à suivre. Une bonne question est : quelle fonction ce composant rend-il aux autres ?

Pour un projet de mesures, la lecture peut convertir les champs d’un CSV en nombres ; le calcul reçoit ensuite une liste numérique déjà validée ; l’affichage reçoit des indicateurs. Une dépendance utile se dessine par une flèche entre ces responsabilités. Une variable globale partagée contournerait cette interface et rendrait les tests moins autonomes.

Lire ce que l’API garantit

Une API est un ensemble d’opérations mises à disposition avec leurs règles d’usage. La documentation précise les noms, les paramètres, leurs types ou domaines, le résultat et les effets observables. Pour une fonction moyenne, on doit savoir si une liste vide est autorisée et comment ce cas est traité.

Un nom plausible ne remplace pas la documentation. Deux opérations peuvent sembler trier une liste, mais l’une modifie la liste reçue tandis que l’autre produit une nouvelle liste. Le choix dépend alors de ce que le programme appelant souhaite conserver. Les erreurs documentées font aussi partie du contrat utile.

Écrire un contrat réellement exploitable

Voici une fonction qui reçoit une séquence non vide de nombres et renvoie leur moyenne, sans la modifier. L’assertion matérialise une précondition pédagogique ; elle ne remplace pas une politique complète de validation de données externes. La documentation annonce explicitement le cas exclu.

def moyenne(valeurs):
    """Renvoie la moyenne d’une séquence non vide de nombres.
    Ne modifie pas valeurs.
    """
    assert len(valeurs) > 0
    return sum(valeurs) / len(valeurs)

Un exemple court complète utilement ce texte : moyenne([2, 4, 9]) renvoie 5.0. Un exemple ne remplace cependant pas la règle générale. La documentation doit permettre d’utiliser la fonction sur d’autres données que celles de la démonstration.

Importer et vérifier les composants

Si cette fonction se trouve dans statistiques.py, on peut écrire import statistiques puis statistiques.moyenne([2, 4, 9]). Le nom qualifié indique l’origine de la fonction et limite certaines ambiguïtés. La forme from statistiques import moyenne est également possible, mais place directement le nom moyenne dans l’espace de noms courant.

Un module destiné à être réutilisé ne devrait pas lancer involontairement une longue démonstration ou demander une saisie lors de son import. En Python, le garde if __name__ == "__main__" permet d’isoler un scénario exécuté seulement lorsque le fichier est lancé directement. On vérifie ensuite le contrat par des tests normaux et des cas limites pertinents.

Exemple suivi : intégrer une fonction documentée

Une API fictive propose normaliser(valeurs, maximum) : elle reçoit une séquence de nombres positifs ou nuls et un maximum strictement positif, renvoie une nouvelle liste où chaque valeur est divisée par ce maximum, sans modifier l’entrée. Avec [2,6] et maximum 8, le résultat attendu est [0.25,0.75]. La sortie nouvelle et l’absence de mutation permettent de conserver les mesures originales.

Avant l’appel, vérifiez le domaine, particulièrement maximum=0. Après l’appel, utilisez la valeur renvoyée : appeler la fonction sans conserver son résultat ne met pas à jour automatiquement votre liste. Un test peut conserver une copie des mesures, appeler la fonction, comparer le résultat attendu et vérifier que l’original n’a pas changé. La documentation décrit les deux propriétés ; lire seulement le nom de la fonction ne permettrait de deviner ni la formule ni son effet sur la mémoire.

Question à lire dans le contratRéponse de cette API fictive
Domaine du maximumNombre strictement positif
Domaine des valeursNombres positifs ou nuls
RésultatNouvelle liste de quotients
Modification de l’entréeAucune
Cas d’une liste videNouvelle liste vide

Exemple suivi : écrire un module réutilisable

Dans indicateurs.py, placez une fonction de calcul recevant ses données en paramètre et renvoyant son résultat. Une démonstration peut être écrite sous if __name__ == "__main__":. Lorsque le fichier est lancé directement, ce bloc s’exécute ; lorsqu’un autre module importe les fonctions, la démonstration ne doit pas demander une saisie ni ouvrir une fenêtre. Cela rend l’import prévisible pour le programme utilisateur et pour les tests.

Une documentation suffisante précise les paramètres, les cas exclus ou acceptés, le résultat, les effets et un exemple. Elle n’a pas besoin d’expliquer le nom de chaque variable locale. Si une boucle est remplacée par une autre méthode respectant les mêmes garanties, les utilisateurs du module ne devraient pas changer leur code. En revanche, remplacer un résultat nouveau par une modification sur place change le contrat : il faut adapter explicitement les appelants et les tests concernés.

À vous de faire varier les choses

Que dit cette information sur une API ?

Classez les éléments d’un contrat. Une même documentation rassemble plusieurs types d’informations complémentaires.

Lire les associations expliquées
La séquence reçue doit contenir au moins un nombre. : Précondition
C’est une obligation avant l’appel.
La fonction renvoie un nombre représentant la moyenne. : Résultat
Cela décrit la valeur transmise à l’appelant.
La liste reçue est triée sur place. : Effet de bord
L’objet du programme appelant est modifié.
Une boucle for accumule les valeurs. : Détail interne
Le calcul pourrait être réalisé autrement sans changer le contrat.
Le paramètre seuil doit être positif. : Précondition
Le domaine d’entrée est restreint.
Un nouveau dictionnaire est renvoyé. : Résultat
Cela précise la nature et la création du résultat.
Un message est écrit dans un fichier journal. : Effet de bord
L’appel modifie un état extérieur au résultat retourné.
Une variable locale se nomme total. : Détail interne
L’utilisateur de l’API n’a normalement pas besoin de ce nom.
La fonction accepte [] et renvoie alors une nouvelle liste vide : classez ici la partie « accepte [] ». : Précondition
Le domaine autorisé comprend le cas vide ; cette précision change les appels valides.
Après une optimisation, le module utilise un dictionnaire local mais conserve entrées, sorties et effets. : Détail interne
La représentation locale relève de l’implémentation. Les utilisateurs gardent le même contrat.
Un calcul renvoie 12 mais ajoute aussi une ligne dans un fichier journal : classez cet ajout. : Effet de bord
L’écriture est observable en dehors de la valeur retournée et doit être annoncée.

Utiliser une API exige son contrat ; changer son implémentation peut préserver ce contrat.

De la compréhension à l’autonomie

À vous de résoudre

Cherchez d’abord par vous-même. Vérifiez les résultats demandés, utilisez les indices si nécessaire, puis comparez votre méthode à la correction.

Exercice 1 · Comprendre#

Trouver l’information manquante

Une documentation dit seulement « calcule une moyenne ». Quelles informations manque-t-il pour utiliser la fonction sans lire son code ?

Indice 1

Pensez aux entrées autorisées.

Indice 2

Pensez à la sortie et aux effets sur les données reçues.

Comprendre la correction

Il manque notamment le type des valeurs, l’acceptation ou non d’une séquence vide, le type ou la signification du résultat et l’absence ou la présence de modification des données. Une documentation utile décrit le contrat observable, pas seulement l’intention générale.

Exercice 2 · Appliquer#

Utiliser un module

La fonction moyenne appartient à statistiques.py. Après import statistiques, comment calculer la moyenne de [3, 6, 9] ?

Indice 1

Utilisez le nom du module devant la fonction.

Indice 2

Le séparateur est un point.

Comprendre la correction

L’appel est statistiques.moyenne([3, 6, 9]). Il renvoie 6.0 selon la fonction présentée. Le nom qualifié identifie le composant utilisé ; la liste non vide respecte la précondition.

Exercice 3 · Corriger#

Respecter une précondition

Un programme appelle moyenne([]) puis affirme que la bibliothèque est défectueuse lorsqu’une assertion échoue. Que faut-il vérifier ?

Indice 1

Relisez le domaine annoncé.

Indice 2

Le composant appelant possède aussi une responsabilité.

Comprendre la correction

La séquence vide viole la précondition annoncée. Le programme appelant doit traiter ce cas avant l’appel ou choisir une API qui définit un résultat pour une absence de données. Une bibliothèque n’a pas à inventer un comportement pour un cas explicitement exclu.

Exercice 4 · Concevoir#

Découper un projet

Un projet lit un CSV de températures, calcule des moyennes et affiche un graphique. Proposez trois responsabilités séparables et un intérêt de ce choix.

Indice 1

Distinguez acquisition, traitement et restitution.

Indice 2

Quel composant peut être testé sur une liste écrite directement ?

Comprendre la correction

Un composant lit et valide le CSV ; un autre calcule les indicateurs ; un troisième présente les résultats. Les calculs peuvent être testés avec des données en mémoire, indépendamment du fichier et de l’affichage. Les échanges entre composants doivent préciser les données transmises.

Exercice 5 · Problème de synthèse#

Problème : tester un contrat complet

L’API fictive normaliser est décrite dans le cours. Préparez un test normal avec [2,6] et maximum 8, un cas de liste vide et une entrée interdite. Précisez ce qui doit rester identique après l’appel et quelle hypothèse supplémentaire serait nécessaire pour imposer des résultats entre zéro et un.

Indice 1

La fonction ne limite pas les valeurs au maximum dans son contrat actuel.

Indice 2

Testez séparément le résultat et l’objet d’entrée.

Comprendre la correction

Le test normal attend [0.25,0.75] et conserve l’entrée [2,6]. La liste vide donne une nouvelle liste vide. maximum=0 viole la précondition. Pour garantir des valeurs au plus égales à un, il faudrait exiger chaque entrée inférieure ou égale au maximum ; les garanties actuelles n’interdisent pas 12/8=1.5.

Exercice 6 · Problème de synthèse#

Problème : corriger une intégration

Le module fictif triutils fournit copie_triee(t), qui renvoie une nouvelle liste croissante sans modifier t. L’appelant fait seulement triutils.copie_triee(notes) puis affiche notes. Expliquez son erreur, corrigez la ligne et proposez un test montrant aussi la conservation de l’original.

Indice 1

Le résultat doit être affecté à un nom.

Indice 2

Utilisez des données initialement non triées.

Comprendre la correction

L’appelant ignore la valeur renvoyée ; notes reste dans son ordre initial conformément au contrat. Il peut écrire resultat = triutils.copie_triee(notes), puis afficher resultat. Avec notes=[9,2,6], resultat doit valoir [2,6,9] et notes doit toujours valoir [9,2,6]. Deux vérifications sont nécessaires, car un tri sur place pourrait produire la bonne sortie tout en violant l’absence de mutation.

Exercice 7 · Problème de synthèse#

Problème : découper une application de mesures

Une application importe des températures, ignore les lignes invalides avec un signalement, calcule minimum et moyenne puis affiche un rapport. Proposez les données échangées entre lecture, calcul et présentation. Indiquez où traiter l’absence de mesure et où tester les calculs. Justifiez deux choix de documentation.

Indice 1

Les erreurs de lecture doivent rester visibles.

Indice 2

Une moyenne n’a pas de valeur numérique naturelle sur une liste vide.

Comprendre la correction

La lecture peut renvoyer les mesures valides et une liste d’erreurs. Le calcul reçoit uniquement les nombres et produit les indicateurs ; l’appelant traite explicitement la liste vide avant une moyenne qui l’exclut. La présentation reçoit indicateurs et signalements. Les calculs se testent sur de petites listes en mémoire. Documenter le vide et l’absence de mutation évite des hypothèses cachées entre composants.

Les erreurs qui méritent un détour

Déduire un effet uniquement du nom de la fonction.
La documentation précise les modifications éventuelles et les résultats.
Créer des dépendances cachées par variables globales.
Des paramètres et retours explicites rendent les composants plus faciles à tester.

La fiche à garder

L’essentiel à retenir

  • Une API décrit des opérations et leurs contrats.
  • Un module regroupe une responsabilité cohérente.
  • Les préconditions, résultats et effets doivent être documentés.

Cette notion au bac

Retrouvez ces idées dans un sujet complet, avec des indices, une correction expliquée et des ateliers.

Le prochain pas

Retrouver le catalogue de Terminale

Ce chapitre s’appuie sur le programme officiel de Terminale (PDF, nouvel onglet). Les explications et exercices sont proposés pour l’apprentissage.