EuraStudy
Fiches/NSI — Numérique et sciences informatiques/Langages et paradigmes de programmation
FR · Bac

Langages et paradigmes de programmation

Ce thème de terminale aborde les grands styles de programmation — impératif, fonctionnel et objet — et met l'accent sur la PROGRAMMATION ORIENTÉE OBJET (classes, attributs, méthodes, instances, constructeur \_\_init\_\_ et encapsulation) ainsi que sur la MISE AU POINT des programmes : spécifier une fonction (préconditions, postconditions, documentation), écrire des jeux de tests, utiliser des assertions et gérer des exceptions. L'idée directrice : tous les langages usuels étant Turing-complets, choisir un paradigme relève du style et de la structuration, et un programme se conçoit avec son contrat puis s'éprouve méthodiquement par les tests.

6 sections·~38 min de lecture·4 compétences·Vérifié · 08/2026

T·0555 / 10
Profil d’examen
Distinguer, sur des exemples de code, les paradigmes impératif, fonctionnel et objet ; choisir un paradigme selon le champ d'application d'un programme, en expliquant que les langages usuels, tous Turing-complets, sont équivalents en pouvoir d'expression.Écrire une classe : définir des attributs et des méthodes, écrire le constructeur \_\_init\_\_, et instancier des objets ; utiliser un objet en accédant à ses attributs et en appelant ses méthodes.Spécifier une fonction par ses préconditions et postconditions et la documenter (docstring) ; distinguer la spécification (le quoi) de l'implémentation (le comment).Mettre au point un programme : prototyper une fonction, l'éprouver sur des jeux de tests pertinents (nominal, limite, erreur), utiliser assertions et exceptions, repérer et corriger les erreurs.
Opérateurs :distingueridentifierécrireinstancierutiliserspécifierdocumentertestercorrigerjustifier
Profondeur

Profondeur de lecture : Approfondi

Texte

Taille du texte : Standard · Interligne : Compact

Toujours charger les médias : désactivé

Sommaire · 6 sections▾
  1. Langages et paradigmes de programmation
    • 01Paradigmes de programmation : impératif, fonctionnel, objet○
    • 02Programmation orientée objet : classes, attributs, méthodes◐
    • 03Instancier et utiliser des objets en Python◐
    • 04Spécifier une fonction : préconditions, postconditions, documentation◐
    • 05Modularité : modules, bibliothèques, API et leur documentation◐
    • 06Mettre au point : jeux de tests, assertions, exceptions●

6 sections · 25 points clés · 7 formules · 30 pièges signalés

§ 01
§ 01

Paradigmes de programmation : impératif, fonctionnel, objet#

~6 min de lecture●○○BaseBOeduscol-programme-nsi-terminale

Trois paradigmes pour un même problème : sommer une liste

Trois paradigmes, un même problèmeTableau de 3 colonnes et 3 lignes, Données: Paradigme · Exemple : sommer L · Idée maîtresse; impératif · s=0 ; for x in L: s+=x · décrire les étapes et l'état (s change); fonctionnel · somme(L) = tête + somme(reste) · composer des fonctions, sans état mutable; objet · p = Pile(L) ; p.total() · structurer : données + méthodes dans un objet, cellule mise en évidence : structurer : données + méthodes dans un objetParadigmeExemple : sommer LIdée maîtresseimpératifs = 0 ; for x in L: s+ = xdécrire les étapes et l'état(s change)fonctionnelsomme(L) = tête +somme(reste)composer des fonctions, sansétat mutableobjetp = Pile(L) ; p.total()structurer : données +méthodes dans un objet
Fig. 1Le même problème, trois styles d'organisation. Tous Turing-complets : même pouvoir d'expression, manières de penser différentes. Le style objet est mis en évidence.

Points clés

Un PARADIGME de programmation est une manière de penser et d'organiser un programme — un « style » qui dicte comment on exprime les calculs et comment on structure le code. Le programme de terminale en distingue trois sur des exemples : impératif, fonctionnel et objet. Ce ne sont pas des langages mais des façons d'utiliser un langage.
Le paradigme IMPÉRATIF décrit le calcul comme une SUITE D'INSTRUCTIONS qui modifient un ÉTAT (le contenu des variables) : affectations, séquences, conditions, boucles. On dit « comment » faire, pas à pas. C'est le style enseigné en première (variables, for, while). Exemple : sommer une liste avec un accumulateur "s" que l'on met à jour dans une boucle.
Le paradigme FONCTIONNEL décrit le calcul comme la COMPOSITION et l'APPLICATION de fonctions, idéalement sans état mutable : on privilégie des fonctions « pures » (mêmes arguments → même résultat, sans effet de bord) et la récursivité plutôt que les boucles. On dit « quoi » calculer. Exemple : sommer une liste comme « tête + somme(reste) », l'élément neutre étant 0 sur la liste vide.
Le paradigme OBJET (programmation orientée objet, POO) STRUCTURE le programme autour d'OBJETS qui regroupent des données (attributs) et les traitements qui agissent sur elles (méthodes). On organise le code autour des « choses » du problème (un compte bancaire, un point, une pile) plutôt qu'autour des actions. C'est le cœur nouveau de la terminale.
Repère essentiel à connaître : tous les langages généralistes usuels (Python, Java, C, OCaml…) sont TURING-COMPLETS, donc ÉQUIVALENTS en pouvoir d'expression — tout ce qui est calculable dans l'un l'est dans les autres. Choisir un paradigme n'augmente donc pas ce que l'on peut calculer : c'est un choix de LISIBILITÉ, de structuration et de maintenance, adapté au problème.
Un même langage (Python notamment) est MULTI-PARADIGME : il permet d'écrire le même programme dans les trois styles, et on les combine couramment dans un projet réel. Le travail attendu n'est pas de classer un langage mais de RECONNAÎTRE, sur un extrait de code, le ou les paradigmes mis en œuvre.

Vocabulaire

→ Cartes
  • paradigmeManière d'organiser un programme et d'exprimer le calcul ; impératif, fonctionnel et objet sont au programme.
  • état mutableEnsemble des valeurs modifiables d'un programme ; le paradigme fonctionnel cherche à s'en passer.
  • effet de bordModification observable en dehors de la valeur renvoyée par une fonction (affichage, écriture, mutation d'un argument).
  • Turing-completSe dit d'un langage capable d'exprimer tout calcul réalisable par une machine de Turing ; c'est le cas des langages généralistes usuels.

Le style FONCTIONNEL : une définition récursive, sans variable mutable

somme(L)={0si L est videteˆte(L)+somme(reste(L))sinon\text{somme}(L) = \begin{cases} 0 & \text{si } L \text{ est vide} \\ \text{tête}(L) + \text{somme}(\text{reste}(L)) & \text{sinon} \end{cases}somme(L)={0teˆte(L)+somme(reste(L))​si L est videsinon​

La même tâche (sommer une liste) s'exprime sans boucle ni accumulateur : élément neutre 0 sur la liste vide, puis composition « tête + somme du reste ». À comparer avec la version impérative à accumulateur.

Choisir un paradigme, c'est choisir un style d'organisation

Choisir un paradigme = choisir un styleGraphe, Un problème → impératif (séquence, boucles, état), Un problème → fonctionnel (fonctions pures), Un problème → objet (classes, encapsulation)Un problèmeimpératif(séquence,boucles, état)fonctionnel(fonctionspures)objet (classes,encapsulation)
Fig. 2Un même problème peut s'aborder dans chacun des trois paradigmes ; un langage comme Python permet les trois et on les combine souvent. Le paradigme objet est mis en évidence.
La lecture charge du contenu depuis YouTube (Google).Ouvrir sur YouTube ↗
La lecture charge du contenu depuis YouTube (Google).Ouvrir sur YouTube ↗
Exemple corrigé

Reconnaître le paradigme d'un extrait de code

Pour chacun des trois extraits suivants, donner le paradigme dominant et justifier en citant l'indice décisif. (A) « s = 0 ; for x in L: s = s + x ; return s ». (B) « def somme(L): return 0 if L == [] else L[0] + somme(L[1:]) ». (C) « p = Pile() ; p.empiler(3) ; p.empiler(7) ; print(p.total()) ».

  1. 01Extrait (A)

    Une variable d'état "s" est initialisée puis modifiée à chaque tour d'une boucle for : on décrit pas à pas COMMENT obtenir le résultat en faisant évoluer l'état. Indice décisif : la boucle qui met à jour une variable.

  2. 02Extrait (B)

    La fonction somme s'appelle elle-même, sans aucune variable mutable ni effet de bord ; le résultat est une composition « L[0] + somme(L[1:]) » avec le cas de base 0 sur la liste vide. Indice décisif : récursivité d'une fonction pure.

  3. 03Extrait (C)

    On crée une instance p d'une classe Pile, puis on appelle des MÉTHODES (empiler, total) sur cet objet, qui encapsule ses données. Indice décisif : un objet sur lequel on appelle des méthodes avec la notation p.methode().

  4. 04Conclusion transversale

    Les trois extraits calculent la même somme : ils sont équivalents en pouvoir d'expression (tous les langages usuels sont Turing-complets). Le choix entre eux est un choix de style et de structuration.

Résultat : (A) impératif (boucle qui met à jour l'état s) ; (B) fonctionnel (fonction récursive pure, sans effet de bord) ; (C) objet (méthodes appelées sur une instance). Les trois résolvent le même problème : la différence est de style, pas de puissance de calcul.

Objectif Bac

  • Objectif Bac : sur un (ou deux) extraits de code donnés, IDENTIFIER et JUSTIFIER le paradigme employé (« impératif car il y a une boucle qui met à jour une variable d'état », « fonctionnel car la fonction est récursive et sans effet de bord », « objet car on définit une classe et on appelle des méthodes sur des instances »).
  • Objectif Bac : expliquer en une ou deux phrases ce que signifie « les langages usuels sont Turing-complets / équivalents », et en déduire que le choix d'un paradigme relève du style et de la structuration, non de la puissance de calcul.
  • Objectif Bac : CHOISIR un paradigme selon le champ d'application — justifier qu'un problème centré sur des « objets » du domaine (un compte, un point, une pile) appelle l'objet, qu'un traitement par transformations successives sans état se prête au fonctionnel, et qu'un calcul pas à pas pilotant un état relève de l'impératif.
  • Objectif Bac : appuyer l'identification d'un paradigme sur un INDICE textuel du code (affectation en boucle, fonction sans effet de bord, appel de méthode sur un objet) et le citer.

Erreurs fréquentes

  • Croire qu'un langage « EST » un paradigme (« Python est impératif », « Java est objet »). La plupart des langages généralistes sont multi-paradigmes ; c'est le CODE écrit, pas le langage, qui relève d'un style donné.
  • Confondre « paradigme fonctionnel » et « écrire des fonctions ». Découper son programme en fonctions (def) est une bonne pratique dans TOUS les paradigmes ; le style fonctionnel se caractérise plutôt par l'absence d'effets de bord et l'usage de fonctions pures et de la récursivité.
  • Penser que l'objet est « plus puissant » que l'impératif. Tous ces styles ont le même pouvoir d'expression (Turing-complétude) ; l'objet apporte une meilleure ORGANISATION pour les gros programmes, pas de nouvelles capacités de calcul.
  • Confondre « impératif » et « procédural » comme s'il s'agissait de deux paradigmes opposés : le procédural est l'impératif organisé en procédures.
  • Prendre l'usage de `map` ou d'une compréhension de liste pour une preuve de programmation fonctionnelle : le critère est l'absence d'état modifié, pas la présence d'une construction particulière.

§ 01

Révision active

On donne trois fonctions Python qui calculent toutes la factorielle de n : (1) une version avec une boucle for et une variable f mise à jour ; (2) une version récursive « fact(n) = 1 si n=0, sinon n*fact(n-1) » sans variable mutable ; (3) une classe Compteur munie d'une méthode factorielle() appelée sur une instance. Pour chacune, nommer le paradigme dominant et justifier en une phrase en citant l'indice décisif dans le code.

S’entraîner sur des exercices associés50 questions sur ce thème→

Rappel actif

Rappelle-toi les points clés — puis révèle.

Sources : Annexe de l'arrêté du 19-7-2019 (NOR MENE1921247A) — programme de spécialité NSI, classe terminale (BO spécial n° 8 du 25 juillet 2019) (Ministère de l'Éducation nationale)

§ 02
§ 02

Programmation orientée objet : classes, attributs, méthodes#

~5 min de lecture●●○StandardBOeduscol-programme-nsi-terminale

La « carte d'identité » d'une classe : attributs et méthodes

Carte d'identité d'une classe : attributs + méthodesTableau de 3 colonnes et 6 lignes, Données: Classe « CompteBancaire » · Catégorie · Rôle; titulaire · attribut · l'état : le nom du titulaire; solde · attribut · l'état : le montant disponible; __init__ · méthode · construit l'objet et initialise l'état; deposer(m) · méthode · augmente le solde de m; retirer(m) · méthode · diminue le solde si possible; afficher() · méthode · le comportement : affiche l'état, cellule mise en évidence : __init__Classe «CompteBancaire »CatégorieRôletitulaireattributl'état : le nom du titulairesoldeattributl'état : le montantdisponible_init_méthodeconstruit l'objet etinitialise l'étatdeposer(m)méthodeaugmente le solde de mretirer(m)méthodediminue le solde si possibleafficher()méthodele comportement : affichel'état
Fig. 3Une classe réunit un ÉTAT (les attributs : titulaire, solde) et un COMPORTEMENT (les méthodes). C'est la carte d'identité du type d'objet ; le constructeur __init__ est mis en évidence.

Points clés

Une CLASSE est un MODÈLE (un « moule ») qui décrit une catégorie d'objets : elle définit les données que chaque objet portera (les ATTRIBUTS) et les opérations qu'on pourra lui appliquer (les MÉTHODES). Un OBJET, ou INSTANCE, est un exemplaire concret produit à partir de ce moule. Vocabulaire clé : la classe est le moule, l'objet est l'exemplaire.
Un ATTRIBUT est une variable attachée à un objet : il représente une partie de son ÉTAT (ex. le solde d'un compte, les coordonnées d'un point). Une MÉTHODE est une fonction définie dans la classe et liée à l'objet : elle agit sur les attributs de cet objet (ex. deposer(montant) modifie le solde). Données et traitements sont ainsi réunis au même endroit.
Le CONSTRUCTEUR est la méthode spéciale qui INITIALISE un objet à sa création. En Python il s'écrit \_\_init\_\_(self, …) : il reçoit en premier paramètre self, qui désigne l'INSTANCE en cours de construction, et il crée les attributs en écrivant self.nom = valeur. self n'est pas un mot-clé magique : c'est simplement le premier paramètre, qui reçoit automatiquement l'objet courant à chaque appel de méthode.
L'ENCAPSULATION consiste à regrouper dans l'objet ses données ET les méthodes qui les manipulent, et à n'exposer qu'une INTERFACE (les méthodes publiques) en cachant les détails internes. On manipule alors l'objet par ses méthodes plutôt qu'en touchant directement ses attributs : le code utilisateur ne dépend pas de la représentation interne, ce qui rend le programme plus robuste et plus facile à faire évoluer.
En Python, on définit une classe avec « class NomClasse: » (par convention en CamelCase), puis ses méthodes en blocs def indentés ; chaque méthode reçoit self en premier paramètre. Les attributs ne sont pas déclarés à l'avance : ils sont créés dynamiquement, le plus souvent dans \_\_init\_\_, par des affectations self.attribut = ….

Vocabulaire

→ Cartes
  • classeModèle décrivant les attributs et les méthodes communs à une catégorie d'objets.
  • instanceObjet créé à partir d'une classe, doté de ses propres valeurs d'attributs.
  • attributVariable attachée à un objet et constituant une partie de son état.
  • méthodeFonction définie dans une classe et appelée sur un objet, qui reçoit cet objet comme premier paramètre.
  • constructeurMéthode spéciale initialisant les attributs d'un objet à sa création ; en Python, `\_\_init\_\_`.

Instancier : du moule (classe) à l'exemplaire (objet)

c = CompteBancaire("Ada", 100)  ⟹  c.solde=100\texttt{c = CompteBancaire("Ada", 100)} \;\Longrightarrow\; \texttt{c.solde} = 100c = CompteBancaire("Ada", 100)⟹c.solde=100

L'appel CompteBancaire("Ada", 100) déclenche __init__ avec self = le nouvel objet ; les affectations self.titulaire = … et self.solde = … fixent l'état initial de l'instance c.

Le constructeur __init__ et le rôle de self

Le constructeur __init__ et le rôle de selfGraphe, c = CompteBancaire('Ada', 100) → __init__(self, titulaire, solde), __init__(self, titulaire, solde) → self = le nouvel objet, self = le nouvel objet → self.titulaire, self.solde initialisésc = CompteBancaire('Ada',100)init(self,)titulaire,solde)self = le nouvelobjetself.titulaire,self.soldeinitialisésappelle
Fig. 4Instancier appelle automatiquement __init__ ; self y désigne le nouvel objet en cours de construction, sur lequel on crée les attributs (self.titulaire, self.solde). Le rôle de self est mis en évidence.
La lecture charge du contenu depuis YouTube (Google).Ouvrir sur YouTube ↗
La lecture charge du contenu depuis YouTube (Google).Ouvrir sur YouTube ↗
Exemple corrigé

Écrire et instancier une classe CompteBancaire

Écrire une classe CompteBancaire avec : les attributs titulaire et solde ; un constructeur \_\_init\_\_(self, titulaire, solde_initial) ; une méthode deposer(self, montant) qui augmente le solde ; une méthode retirer(self, montant) qui diminue le solde si possible. Créer ensuite le compte de « Ada » avec un solde initial de 100, déposer 50, retirer 30, puis donner le solde final.

  1. 01Définir la classe et le constructeur

    On écrit « class CompteBancaire: » puis « def __init__(self, titulaire, solde_initial): » qui crée self.titulaire = titulaire et self.solde = solde_initial. self reçoit automatiquement le nouvel objet.

  2. 02Ajouter les méthodes

    deposer(self, montant) fait self.solde = self.solde + montant. retirer(self, montant) ne diminue le solde que si montant <= self.solde (sinon il refuse l'opération). Chaque méthode agit sur l'attribut via self.

  3. 03Instancier puis appeler les méthodes

    c = CompteBancaire('Ada', 100) crée l'objet (solde 100). c.deposer(50) porte le solde à 150. c.retirer(30) le ramène à 120 (30 <= 150, l'opération est autorisée).

  4. 04Lire l'état final

    On lit l'attribut de l'objet : c.solde vaut 120. La classe (moule) a produit un objet c (exemplaire) dont les méthodes ont fait évoluer l'état.

Résultat : Après c = CompteBancaire('Ada', 100), c.deposer(50) puis c.retirer(30), l'attribut c.solde vaut 120. La classe est le moule, c est l'instance, deposer/retirer sont des méthodes qui modifient l'attribut solde via self.

Objectif Bac

  • Objectif Bac : ÉCRIRE une classe complète à partir d'un énoncé — choisir des attributs pertinents, écrire le constructeur \_\_init\_\_ qui les initialise, et définir des méthodes qui agissent sur self (lecture, modification, affichage).
  • Objectif Bac : maîtriser le vocabulaire et savoir l'utiliser à bon escient dans une justification — distinguer classe et instance, attribut et méthode, et expliquer le rôle de \_\_init\_\_ et de self sur un exemple.
  • Objectif Bac : écrire `\_\_init\_\_` en initialisant TOUS les attributs annoncés dans l'énoncé, et vérifier que chacun est ensuite utilisé par au moins une méthode.
  • Objectif Bac : nommer les méthodes par le VERBE de l'action décrite dans l'énoncé (`deposer`, `retirer`, `est_a_decouvert`), ce qui rend la classe lisible sans commentaire.
  • Objectif Bac : justifier l'encapsulation par un scénario concret — ce qui casserait si le code appelant modifiait directement l'attribut.

Erreurs fréquentes

  • Oublier self : écrire « def deposer(montant): » au lieu de « def deposer(self, montant): », ou écrire « solde = solde + montant » au lieu de « self.solde = self.solde + montant ». Sans self, on manipule une variable locale, pas l'attribut de l'objet, et la modification est perdue.
  • Confondre la CLASSE et l'INSTANCE : « CompteBancaire » est le moule, « c = CompteBancaire('Ada', 100) » est un objet. On appelle les méthodes sur l'objet (c.deposer(50)), pas sur la classe.
  • Croire que \_\_init\_\_ « renvoie » l'objet : \_\_init\_\_ ne fait qu'initialiser les attributs de self ; il ne doit rien renvoyer (return None implicite). C'est l'appel NomClasse(...) qui crée l'objet et renvoie l'instance.
  • Déclarer les attributs au niveau de la classe (`solde = 0` sous `class`) en croyant les rendre propres à chaque objet : ils deviennent alors partagés par toutes les instances.
  • Ajouter un `return self` à la fin de `\_\_init\_\_` : cette méthode ne renvoie rien, et un `return` d'une valeur autre que None y provoque une TypeError.

§ 02

Révision active

Écrire en Python une classe Rectangle dotée des attributs largeur et hauteur, d'un constructeur \_\_init\_\_(self, largeur, hauteur) qui les initialise, et de deux méthodes aire(self) et perimetre(self) qui renvoient respectivement l'aire et le périmètre. Créer ensuite un rectangle 4 × 3 et vérifier que aire() vaut 12 et perimetre() vaut 14.

S’entraîner sur des exercices associés50 questions sur ce thème→

Rappel actif

Rappelle-toi les points clés — puis révèle.

Sources : Annexe de l'arrêté du 19-7-2019 (NOR MENE1921247A) — programme de spécialité NSI, classe terminale (BO spécial n° 8 du 25 juillet 2019) (Ministère de l'Éducation nationale)

§ 03
§ 03

Instancier et utiliser des objets en Python#

~6 min de lecture●●○StandardBOeduscol-programme-nsi-terminale

Un moule, plusieurs instances : des objets distincts

Un moule (la classe), plusieurs instances distinctesGraphe, Point (le moule : x, y) → a = Point(0, 0), Point (le moule : x, y) → b = Point(3, 4), Point (le moule : x, y) → c = Point(3, 4)Point (le moule: x, y)a = Point(0, 0)b = Point(3, 4)c = Point(3, 4)instancierinstancierinstancier
Fig. 5La classe (mise en évidence) est un moule ; chaque instanciation produit un objet distinct avec son propre état. b et c ont les mêmes valeurs (3, 4) mais sont deux objets différents (b is c vaut Faux).

Points clés

INSTANCIER, c'est créer un objet à partir d'une classe en appelant la classe comme une fonction : « b = Point(3, 4) ». Cet appel déclenche \_\_init\_\_ (avec self lié au nouvel objet), initialise les attributs, puis renvoie l'instance, que l'on range ici dans la variable b. Une même classe peut produire AUTANT d'instances que l'on veut, chacune avec son propre état.
ACCÉDER À UN ATTRIBUT se fait avec la notation pointée objet.attribut, SANS parenthèses : « b.x » lit (ou « b.x = 5 » modifie) la donnée x de l'objet b. C'est une valeur, pas une action.
APPELER UNE MÉTHODE se fait avec objet.methode(arguments), AVEC parenthèses : « b.norme() ». Les parenthèses déclenchent l'exécution ; Python passe automatiquement l'objet b comme premier paramètre self de la méthode. Ainsi b.norme() exécute norme(self) avec self = b.
Deux instances issues du même moule sont des objets DISTINCTS, même si leurs attributs ont les mêmes valeurs : « b = Point(3,4) » et « c = Point(3,4) » occupent deux emplacements mémoire différents. Modifier b.x ne change pas c.x. Chaque objet possède son propre jeu d'attributs (son état).
Distinction décisive à l'usage : un ATTRIBUT s'écrit SANS parenthèses (b.x — une donnée), une MÉTHODE s'écrit AVEC parenthèses (b.norme() — une action). Oublier les parenthèses sur une méthode ne provoque pas d'erreur immédiate : Python renvoie alors l'objet « fonction » sans l'exécuter, ce qui est un piège fréquent.
Un piège d'affectation revient à chaque série d'exercices sur les objets, et il n'a rien à voir avec la POO : il tient au fait qu'en Python une variable est un NOM posé sur un objet, pas une boîte contenant une copie. Après `b = Point(3, 4)` puis `c = b`, les deux noms désignent le MÊME objet : `c.x = 10` change aussi ce que lit `b.x`. Après `b = Point(3, 4)` puis `c = Point(3, 4)`, ce sont deux objets distincts qui portent les mêmes valeurs, et modifier l'un laisse l'autre intact. Le test `b is c` distingue les deux situations : il compare les identités, là où `b == c` compare selon la règle définie par la classe — l'identité, elle aussi, tant qu'aucune méthode de comparaison n'a été écrite.

Vocabulaire

→ Cartes
  • instancierCréer un objet à partir d'une classe en appelant celle-ci comme une fonction.
  • notation pointéeÉcriture `objet.attribut` ou `objet.methode(...)` donnant accès aux membres d'un objet.
  • selfPremier paramètre de toute méthode, automatiquement lié à l'objet sur lequel la méthode est appelée.
  • identité d’un objetCe qui distingue deux objets même lorsqu'ils portent les mêmes valeurs d'attributs.

Appeler une méthode : la liaison automatique de self

b.norme() ≡ Point.norme(b)⇒self=b\texttt{b.norme()}\ \equiv\ \texttt{Point.norme(b)} \quad\Rightarrow\quad \texttt{self} = \texttt{b}b.norme() ≡ Point.norme(b)⇒self=b

La notation pointée b.norme() est équivalente à appeler la fonction de la classe en lui passant b comme premier argument self. C'est pourquoi on n'écrit jamais soi-même b.norme(b).

Exemple de calcul réalisé par une méthode (point (3 ; 4))

norme(b)=b.x2+b.y2=32+42=25=5\text{norme}(b) = \sqrt{b.x^{2} + b.y^{2}} = \sqrt{3^{2} + 4^{2}} = \sqrt{25} = 5norme(b)=b.x2+b.y2​=32+42​=25​=5

La méthode norme lit les attributs x et y de l'objet et renvoie la distance à l'origine. Pour b = Point(3, 4), elle vaut 5.

Attribut sans parenthèses, méthode avec parenthèses

Attribut (lecture) contre méthode (appel)Tableau de 3 colonnes et 2 lignes, Données: Accès · Syntaxe · Effet; attribut · b.x · lit la donnée stockée (3), sans parenthèses; méthode · b.norme() · exécute le code et renvoie un résultat (5.0), cellule mise en évidence : b.norme()AccèsSyntaxeEffetattributb.xlit la donnée stockée (3),sans parenthèsesméthodeb.norme()exécute le code et renvoieun résultat (5.0)
Fig. 6Un attribut se LIT (pas de parenthèses) ; une méthode s'APPELLE (parenthèses), elle exécute du code et renvoie un résultat. L'appel de méthode (mis en évidence) équivaut à Point.norme(b).
La lecture charge du contenu depuis YouTube (Google).Ouvrir sur YouTube ↗
Exemple corrigé

Utiliser des objets Point : attributs et méthodes

La classe Point(x, y) possède une méthode norme(self) renvoyant la distance à l'origine. (a) Instancier b = Point(3, 4) et c = Point(6, 8). (b) Calculer b.norme() et c.norme(). (c) Donner b.x. (d) Après b.x = 0, la valeur de c.x change-t-elle ?

  1. 01(a) Instancier

    b = Point(3, 4) crée un objet d'attributs b.x = 3 et b.y = 4. c = Point(6, 8) crée un AUTRE objet d'attributs c.x = 6 et c.y = 8. Deux instances indépendantes.

  2. 02(b) Appeler la méthode norme

    b.norme() exécute norme(self) avec self = b : racine de 3^2 + 4^2 = 25, soit 5. c.norme() avec self = c : racine de 6^2 + 8^2 = 100, soit 10.

  3. 03(c) Lire un attribut

    b.x est un accès en lecture à la donnée x de l'objet b : il vaut 3. Pas de parenthèses : c'est une valeur, pas un appel.

  4. 04(d) Indépendance des instances

    b et c sont deux objets distincts, chacun avec son propre attribut x. L'affectation b.x = 0 ne modifie que l'objet b ; c.x reste égal à 6.

Résultat : (a) deux objets indépendants. (b) b.norme() = 5 et c.norme() = 10. (c) b.x = 3. (d) Non : c.x reste 6, car b et c sont des instances distinctes possédant chacune leur propre état.

Objectif Bac

  • Objectif Bac : à partir d'une classe fournie, INSTANCIER un ou plusieurs objets, LIRE et MODIFIER leurs attributs, et APPELER leurs méthodes avec la bonne syntaxe pointée (parenthèses pour les méthodes, pas pour les attributs).
  • Objectif Bac : prédire l'effet d'une suite d'instructions sur l'état de plusieurs objets — notamment comprendre que deux instances sont indépendantes et que modifier l'une ne touche pas l'autre.
  • Objectif Bac : tenir un tableau d'état — une colonne par objet, une ligne par instruction — pour prédire l'effet d'une suite d'affectations et d'appels de méthodes.
  • Objectif Bac : reconnaître qu'une affectation `c = b` entre objets ne copie pas l'objet mais ajoute un second nom sur le même objet, si bien qu'une modification est visible par les deux noms.

Erreurs fréquentes

  • Confondre attribut et méthode dans la syntaxe : écrire b.norme (sans parenthèses) attendu pour obtenir une valeur ne calcule rien — Python renvoie la méthode elle-même ; il faut b.norme(). Inversement, b.x() (avec parenthèses sur un attribut) provoque une erreur car x n'est pas appelable.
  • Croire que deux instances aux mêmes valeurs sont « le même objet » : b = Point(3,4) et c = Point(3,4) sont deux objets distincts ; b == c peut être faux et b.x = 9 ne modifie pas c.x.
  • Passer soi-même self lors de l'appel : on écrit b.norme(), pas b.norme(b) ni Point.norme() — Python relie automatiquement self à l'objet placé avant le point.
  • Croire que `b == c` compare les attributs : sans méthode `\_\_eq\_\_` définie, Python compare les identités, et deux instances distinctes sont différentes.

§ 03

Révision active

On dispose d'une classe Point(x, y) munie d'une méthode norme(self) qui renvoie la distance à l'origine. (a) Instancier deux points b = Point(3, 4) et c = Point(6, 8). (b) Donner la valeur de b.norme() et de c.norme(). (c) Que renvoie b.x ? (d) Après l'instruction b.x = 0, la valeur de c.x est-elle modifiée ? Justifier.

S’entraîner sur des exercices associés50 questions sur ce thème→

Rappel actif

Rappelle-toi les points clés — puis révèle.

Sources : Annexe de l'arrêté du 19-7-2019 (NOR MENE1921247A) — programme de spécialité NSI, classe terminale (BO spécial n° 8 du 25 juillet 2019) (Ministère de l'Éducation nationale)

§ 04
§ 04

Spécifier une fonction : préconditions, postconditions, documentation#

~5 min de lecture●●○StandardBOeduscol-programme-nsi-terminale

Le contrat d'une fonction : précondition, fonction, postcondition

Le contrat d'une fonction : pré → fonction → postGraphe, Précondition : x ≥ 0 (à la charge de l'appelant) → Fonction racine(x), Fonction racine(x) → Postcondition : r ≥ 0 et r² = xPrécondition : x≥ 0 (à la chargede l'appelant)Fonctionracine(x)Postcondition :r ≥ 0 et r² = xsi vraiealors garantit
Fig. 7Le contrat d'une fonction : si l'appelant garantit la précondition (en entrée), alors la fonction (mise en évidence) garantit la postcondition (en sortie). Spécifier, c'est écrire ce contrat avant de coder.

Points clés

SPÉCIFIER une fonction, c'est décrire son CONTRAT : ce qu'elle prend en entrée, ce qu'elle renvoie, et sous quelles hypothèses — indépendamment de la façon dont elle est codée. La spécification dit CE QUE fait la fonction ; le code dit COMMENT. On peut tester ou raisonner sur une fonction à partir de sa seule spécification.
Une PRÉCONDITION est une propriété qui doit être VRAIE AU MOMENT DE L'APPEL pour que la fonction fonctionne correctement (ex. pour racine(x), la précondition « x >= 0 »). C'est à l'APPELANT de la garantir. Si une précondition n'est pas respectée, la fonction n'est pas tenue de donner un résultat correct.
Une POSTCONDITION est une propriété GARANTIE EN SORTIE, à condition que les préconditions aient été respectées (ex. pour racine(x) : le résultat r vérifie r >= 0 et r*r = x). C'est à la FONCTION de l'assurer. Préconditions et postconditions forment ensemble le contrat : « si tu me donnes des entrées valides, je te rends un résultat conforme ».
DOCUMENTER une fonction en Python se fait avec un DOCSTRING : une chaîne placée juste sous l'en-tête def, qui décrit le rôle de la fonction, le sens et le type de ses paramètres, la valeur renvoyée, et ses préconditions/postconditions. Le docstring est lisible par help() et fait partie du code : il en constitue la spécification écrite.
Une bonne spécification est PRÉCISE et VÉRIFIABLE : elle nomme les variables, donne leur type et leurs contraintes, et formule la postcondition comme une propriété qu'on pourrait tester (ex. par une assertion). Spécifier AVANT de coder aide à concevoir les bons tests et clarifie le comportement attendu, y compris dans les cas limites.

Vocabulaire

→ Cartes
  • spécificationDescription du contrat d'une fonction : entrées, sortie, préconditions et postcondition.
  • postconditionPropriété du résultat garantie par la fonction lorsque les préconditions sont respectées.
  • docstringChaîne de documentation placée sous l'en-tête d'une fonction et accessible à l'exécution.
  • contratAccord entre l'appelant, qui garantit les préconditions, et la fonction, qui garantit la postcondition.

Le contrat d'une fonction : précondition → fonction → postcondition

x≥0⏟preˊcondition (appelant)  ⟶  r = racine(x)  ⟶  r≥0 et r2=x⏟postcondition (fonction)\underbrace{x \ge 0}_{\text{précondition (appelant)}} \;\longrightarrow\; \texttt{r = racine(x)} \;\longrightarrow\; \underbrace{r \ge 0 \ \text{et}\ r^{2} = x}_{\text{postcondition (fonction)}}preˊcondition (appelant)x≥0​​⟶r = racine(x)⟶postcondition (fonction)r≥0 et r2=x​​

Si l'appelant garantit la précondition x >= 0, la fonction garantit en retour la postcondition « r positif et r au carré égal à x ». Hors précondition, aucune garantie.

La lecture charge du contenu depuis YouTube (Google).Ouvrir sur YouTube ↗
Exemple corrigé

Spécifier et documenter une fonction de division entière

On veut une fonction quotient_reste(a, b) qui renvoie le couple (q, r) du quotient et du reste de la division euclidienne de a par b, pour a et b entiers. (a) Donner la précondition. (b) Donner la postcondition liant a, b, q et r. (c) Rédiger un docstring Python conforme.

  1. 01(a) Précondition

    La division euclidienne n'a de sens que si le diviseur n'est pas nul. On impose donc, à la charge de l'appelant : a et b entiers, et b différent de 0 (on prendra ici b > 0 pour fixer le signe du reste).

  2. 02(b) Postcondition

    La fonction garantit que le couple renvoyé reconstitue a et que le reste est dans le bon intervalle : a = b*q + r avec 0 <= r < b. C'est une propriété vérifiable (testable par assertion).

  3. 03(c) Docstring

    Sous l'en-tête def quotient_reste(a, b):, on place une chaîne triple décrivant le QUOI : « Renvoie (q, r) tels que a = b*q + r et 0 <= r < b. Precondition : a entier, b entier strictement positif. » Le docstring est la spécification écrite, lisible par help().

  4. 04Vérification sur un exemple

    Pour a = 17, b = 5 : q = 3, r = 2. On vérifie la postcondition : 5*3 + 2 = 17 et 0 <= 2 < 5. Le contrat est tenu.

Résultat : Précondition : a, b entiers avec b > 0. Postcondition : a = b*q + r et 0 <= r < b. Le docstring décrit le résultat (le QUOI) et les hypothèses, sans détailler l'algorithme. Exemple : quotient_reste(17, 5) = (3, 2), conforme au contrat.

Objectif Bac

  • Objectif Bac : à partir d'un énoncé, RÉDIGER la spécification d'une fonction — préconditions sur les entrées, postcondition sur la sortie — et la traduire en un docstring clair.
  • Objectif Bac : à partir d'un docstring/spécification donné, JUSTIFIER si un appel est valide (préconditions respectées) et dire ce qui est garanti en retour (postcondition), ou repérer un appel qui viole le contrat.
  • Objectif Bac : formuler la postcondition comme une propriété du RÉSULTAT (« renvoie le plus petit élément de t »), jamais comme la description de l'algorithme employé.
  • Objectif Bac : traduire une précondition en `assert` en tête de fonction lorsque l'énoncé demande de la faire respecter, et savoir dire ce qui se passe si elle échoue.

Erreurs fréquentes

  • Confondre PRÉCONDITION (à la charge de l'appelant, vérifiée à l'entrée) et POSTCONDITION (à la charge de la fonction, vraie en sortie). Mettre « le résultat est positif » en précondition n'a pas de sens : c'est une postcondition.
  • Spécifier le COMMENT au lieu du QUOI : un docstring du type « on fait une boucle qui additionne » décrit l'implémentation. La spécification doit décrire le résultat (ex. « renvoie la somme des éléments de la liste L »), pas l'algorithme.
  • Oublier les cas limites dans la spécification : préciser le comportement sur l'entrée vide, sur 0, sur une liste à un élément, etc. Une postcondition silencieuse sur ces cas mène à des bugs et à des tests incomplets.
  • Écrire une spécification qui ne mentionne pas les types ni les contraintes des paramètres : « prend une liste » est insuffisant si l'algorithme exige une liste NON VIDE de nombres.
  • Placer la vérification d'une précondition dans un `if` qui renvoie une valeur par défaut : la fonction masque alors l'erreur de l'appelant au lieu de la signaler.

§ 04

Révision active

Spécifier puis documenter (par un docstring) une fonction indice_max(L) qui renvoie l'indice d'un plus grand élément d'une liste de nombres L. Préciser la précondition (que faut-il imposer à L pour que la question ait un sens ?), la postcondition (quelle propriété l'indice renvoyé vérifie-t-il ?), et le comportement choisi en cas d'égalité entre plusieurs maximums.

S’entraîner sur des exercices associés50 questions sur ce thème→

Rappel actif

Rappelle-toi les points clés — puis révèle.

Sources : Annexe de l'arrêté du 19-7-2019 (NOR MENE1921247A) — programme de spécialité NSI, classe terminale (BO spécial n° 8 du 25 juillet 2019) (Ministère de l'Éducation nationale)

§ 05
§ 05

Modularité : modules, bibliothèques, API et leur documentation#

~7 min de lecture●●○StandardBOeduscol-programme-nsi-terminale

Un programme, ses modules et leur documentation

Un programme, ses modules et leur documentationGraphe, programme principal : trajet.py → module écrit par vous : geometrie.py, module écrit par vous : geometrie.py → bibliothèque standard : math, csv, module écrit par vous : geometrie.py → documentation : docstring et aide en ligneprogrammeprincipal :trajet.pymodule écrit parvous :geometrie.pybibliothèquestandard : math,csvdocumentation :docstring etaide en ligneimportgeometrieimport mathdécrit soninterface
Fig. 8Le programme principal importe votre module (mis en évidence), qui s'appuie à son tour sur la bibliothèque standard et expose son contrat par ses docstrings. Chaque flèche est une dépendance : on programme contre l'interface de ce qui est en dessous, jamais contre son code.

Points clés

Un MODULE est un fichier de code que d'autres programmes peuvent utiliser. Écrire `import geometrie` cherche le fichier `geometrie.py`, l'exécute une fois, et rend son contenu accessible sous le préfixe `geometrie.` — `geometrie.distance(a, b)`. Le préfixe n'est pas une contrainte de syntaxe : il crée un ESPACE DE NOMS, si bien que votre `distance` et celle d'une autre bibliothèque peuvent coexister sans se recouvrir. C'est la raison pour laquelle `from geometrie import *`, qui déverse tous les noms dans l'espace courant, est déconseillé : deux fonctions homonymes s'écrasent silencieusement et l'erreur ne se manifeste que bien plus tard.
Une BIBLIOTHÈQUE est un ensemble de modules distribué comme un tout : la bibliothèque standard de Python (`math`, `random`, `csv`, `collections`, `sqlite3`) est livrée avec l'interpréteur, d'autres s'installent. Une API — interface de programmation applicative — est le CONTRAT d'utilisation qu'une bibliothèque, un service en ligne ou même un composant matériel expose : la liste des fonctions appelables, leurs paramètres, leurs valeurs de retour et leurs conditions d'emploi. Le mot désigne l'interface, jamais le code qui la réalise ; c'est exactement la distinction interface / implémentation du thème « structures de données », transposée à l'échelle d'une bibliothèque entière.
EXPLOITER une documentation est une capacité attendue en soi, et elle s'exerce. Devant une fonction inconnue, on cherche quatre choses, dans cet ordre : ce qu'elle RENVOIE (une valeur ? une modification en place ? les deux ?), ses paramètres OBLIGATOIRES et leur type, ses paramètres OPTIONNELS avec leur valeur par défaut, et ses conditions d'emploi — ce qu'elle exige et ce qu'elle lève comme exception. Depuis l'interpréteur, `help(objet)` affiche le docstring d'un module, d'une classe ou d'une fonction ; `dir(module)` en énumère les noms publics. Une réponse qui invoque une fonction sans vérifier ce qu'elle renvoie est une réponse à moitié écrite.
CRÉER un module simple et le DOCUMENTER se réduit à trois gestes. Regrouper dans un fichier les fonctions qui traitent d'un même sujet, avec des noms parlants. Placer en tête du fichier un docstring de module disant ce que le module contient et à quoi il sert, puis un docstring sous chaque fonction rappelant son contrat — paramètres, valeur de retour, préconditions. Enfin protéger le code de démonstration ou de test par `if __name__ == '__main__':`, faute de quoi ce code s'exécuterait à chaque importation du module par un autre programme. Un module correctement écrit s'utilise sans jamais l'ouvrir : c'est le test.
La modularité rejoint deux autres thèmes du programme, et l'examen aime ces ponts. Côté STRUCTURES DE DONNÉES, une bibliothèque n'est qu'un type abstrait à grande échelle : on programme contre son interface, on ignore son implémentation, et l'implémentation peut changer d'une version à l'autre sans casser votre code. Côté ARCHITECTURES MATÉRIELLES, le programme note qu'un système sur puce se conçoit de façon logicielle et que ses briques électroniques sont « accessibles par des API, comme pour les bibliothèques logicielles » : la même idée d'interface stable au-dessus d'une réalisation cachée gouverne le logiciel et le matériel.

Vocabulaire

→ Cartes
  • moduleFichier de code importable, dont les noms deviennent accessibles sous un préfixe.
  • bibliothèqueEnsemble de modules distribué comme un tout, standard ou installé séparément.
  • APIInterface de programmation : le contrat des fonctions appelables, de leurs paramètres et de leurs garanties.
  • espace de nomsPortée qui qualifie les noms d'un module et empêche les collisions avec ceux du programme appelant.
  • docstringChaîne de documentation placée en tête d'un module, d'une classe ou d'une fonction, et lisible par `help()`.

Importer, c'est créer un espace de noms

import module  ⟹  module.fonction(...)\texttt{import module} \;\Longrightarrow\; \texttt{module.fonction(...)}import module⟹module.fonction(...)

`module` désigne le fichier `module.py` trouvé dans le chemin de recherche de Python ; le préfixe `module.` qualifie chaque nom qu'il définit, ce qui empêche toute collision avec les noms du programme appelant. La forme `from module import nom` importe un seul nom sans préfixe, et `from module import *` les importe tous — au risque d'écraser les vôtres.

La lecture charge du contenu depuis YouTube (Google).Ouvrir sur YouTube ↗
Exemple corrigé

Lire une documentation et en déduire un appel correct

La documentation d'une fonction d'un module `fichiers` indique : `lire_colonnes(chemin, separateur=',', entete=True) -> list[dict]` — « Renvoie la liste des lignes du fichier CSV situé à `chemin`, chaque ligne étant un dictionnaire dont les clés sont les noms de colonnes. Précondition : le fichier existe et est lisible. Lève `FileNotFoundError` sinon. Si `entete` vaut False, les clés sont les indices de colonne sous forme de chaînes. » (a) Quels paramètres devez-vous fournir ? (b) Écrivez l'appel pour un fichier `notes.tsv` séparé par des tabulations et pourvu d'un en-tête. (c) Que vaut `resultat[0]['nom']` et quel type a-t-il ? (d) Comment protéger l'appel contre un chemin erroné ?

  1. 01Repérer l'obligatoire et l'optionnel

    Un seul paramètre est obligatoire, `chemin`, puisque `separateur` et `entete` portent une valeur par défaut. La documentation impose donc un unique argument minimal ; les deux autres ne s'écrivent que si l'on veut s'écarter du comportement par défaut.

  2. 02Écrire l'appel

    Le fichier est séparé par des tabulations, il faut donc remplacer la valeur par défaut de `separateur` ; l'en-tête est présent, donc `entete` garde sa valeur par défaut et ne s'écrit pas. On nomme l'argument optionnel pour la lisibilité, ce que la documentation autorise.

    Appel avec le seul argument optionnel utile

    lignes = fichiers.lire_colonnes(’notes.tsv’, separateur=’\t’)\texttt{lignes = fichiers.lire\_colonnes('notes.tsv', separateur='\textbackslash t')}lignes = fichiers.lire_colonnes(’notes.tsv’, separateur=’\t’)

    `separateur` est nommé pour la lisibilité et vaut ici la tabulation ; `entete` garde sa valeur par défaut True et ne s'écrit donc pas. `lignes` reçoit la liste de dictionnaires annoncée par la signature.

  3. 03Déduire le type du résultat

    La signature annonce `list[dict]` : `lignes` est une liste, `lignes[0]` est un dictionnaire, et `lignes[0]['nom']` est la valeur associée à la clé `'nom'` dans la première ligne de données. Rien dans la documentation ne promet une conversion de type : la valeur est une CHAÎNE, même si la colonne ne contient que des chiffres.

  4. 04Protéger l'appel

    La documentation nomme l'exception levée quand la précondition n'est pas satisfaite. On entoure donc l'appel d'un `try` / `except FileNotFoundError` qui affiche un message utile, plutôt que d'un `except` nu qui masquerait toute autre erreur.

Résultat : L'appel correct est `fichiers.lire_colonnes('notes.tsv', separateur='\t')`, `lignes[0]['nom']` est une chaîne de caractères, et l'appel se protège par `except FileNotFoundError`. La documentation a suffi : aucune ligne du code de la fonction n'a été lue — c'est exactement ce qu'une API garantit.

Objectif Bac

  • Objectif Bac : définir une API comme un CONTRAT d'utilisation — les fonctions appelables et leurs conditions d'emploi — et non comme un morceau de code ou un service en ligne.
  • Objectif Bac : lire la documentation d'une fonction fournie dans un sujet et en extraire la valeur de retour, les paramètres obligatoires et les préconditions AVANT de l'appeler.
  • Objectif Bac : écrire un module de quelques fonctions cohérentes, avec docstring de module et docstring par fonction, et l'importer depuis un programme principal.
  • Objectif Bac : justifier l'usage d'un module par ce qu'il apporte — réutilisation, espace de noms séparé, mise au point isolée — plutôt que par « c'est plus propre ».

Erreurs fréquentes

  • Employer `from module import *` : les noms importés écrasent silencieusement les vôtres, et l'on ne sait plus, en lisant le code, d'où vient une fonction.
  • Nommer son fichier comme un module standard (`math.py`, `random.py`, `csv.py`) dans le dossier de travail : Python importe alors VOTRE fichier à la place du module standard, et les erreurs qui suivent sont incompréhensibles.
  • Laisser du code de test au niveau du fichier sans le protéger par `if __name__ == '__main__':` : il s'exécute à chaque importation, ce qui pollue le programme appelant.
  • Confondre une API et une bibliothèque : la bibliothèque est le code livré, l'API est la description de ce que l'on a le droit d'en appeler et de ce que cela garantit.
  • Recopier un exemple de documentation sans lire ce que la fonction RENVOIE : une méthode qui trie en place (`liste.sort()`) renvoie `None`, et `t = liste.sort()` met `None` dans `t`.

§ 05

Révision active

Vous disposez d'un module `statistiques.py` contenant `moyenne(t)`, `ecart_type(t)` et `mediane(t)`. (a) Écrivez le docstring du module et celui de `mediane`, en précisant précondition et valeur de retour. (b) Écrivez le programme principal `analyse.py` qui importe ce module, lit une liste de notes et affiche les trois indicateurs. (c) Expliquez ce qui changerait dans `analyse.py` si l'auteur de `statistiques.py` remplaçait son tri interne par un autre algorithme — et pourquoi.

S’entraîner sur des exercices associés50 questions sur ce thème→

Rappel actif

Rappelle-toi les points clés — puis révèle.

Sources : Annexe de l'arrêté du 19-7-2019 (NOR MENE1921247A) — programme de spécialité NSI, classe terminale (Ministère de l'Éducation nationale et de la Jeunesse — BO spécial n° 8 du 25 juillet 2019) · Modules et paquets — documentation officielle du langage Python 3 (français) (Python Software Foundation)

§ 06
§ 06

Mettre au point : jeux de tests, assertions, exceptions#

~7 min de lecture●●●ApprofondissementBOeduscol-programme-nsi-terminale

Le cycle de mise au point : spécifier, coder, tester, corriger

Le cycle de mise au pointGraphe, Spécifier → Coder, Coder → Tester, Tester → Corriger, Corriger → SpécifierSpécifierCoderTesterCorriger
Fig. 9Mettre au point un programme est un cycle : spécifier, coder, tester (mis en évidence), corriger — et l'on boucle entre tester et corriger jusqu'à ce que tous les tests passent.

Points clés

METTRE AU POINT un programme, c'est l'éprouver pour repérer et corriger ses erreurs. Le cycle attendu est : SPÉCIFIER (le contrat) → CODER → TESTER → CORRIGER, en bouclant tester/corriger jusqu'à ce que tous les tests passent. Tester ne prouve pas l'absence de bugs, mais des tests bien choisis donnent une forte confiance dans le comportement.
Un JEU DE TESTS est un ensemble de cas (entrée → sortie attendue) qui documente et vérifie le comportement. Un bon jeu de tests couvre TROIS familles : les cas NOMINAUX (situations courantes), les cas LIMITES (frontières : liste vide, n = 0, n = 1, valeur minimale ou maximale) et les cas D'ERREUR (entrées invalides au regard de la précondition). Les cas limites et d'erreur sont les plus révélateurs de bugs.
Une ASSERTION (instruction assert en Python) vérifie qu'une propriété est vraie à un point du programme : « assert condition, message ». Si la condition est vraie, l'exécution continue ; si elle est fausse, Python lève une AssertionError et arrête le programme. Les assertions servent à tester (postconditions, invariants) et à détecter tôt une violation de contrat — pas à valider des entrées utilisateur en production.
Une EXCEPTION est un événement qui interrompt le cours normal du programme lorsqu'une erreur survient (division par zéro → ZeroDivisionError, indice hors limites → IndexError, valeur invalide → ValueError…). On peut la PROVOQUER volontairement avec raise (ex. raise ValueError("x doit être positif")) pour signaler une précondition violée.
GÉRER une exception se fait avec le bloc try / except : on place le code « à risque » dans try, et le code de récupération dans except TypeDException. Si l'exception visée survient, elle est RATTRAPÉE et l'on exécute le bloc except au lieu de planter. Cela permet de réagir proprement à une erreur prévue (afficher un message, redemander une saisie) plutôt que d'interrompre brutalement le programme.
PROTOTYPER puis ÉPROUVER : on écrit une première version d'une fonction, on la confronte à un jeu de tests pertinent (nominal, limite, erreur), on observe les échecs, on localise le bug, on corrige, et on relance les tests. Garder ses tests permet de vérifier qu'une correction ne casse rien d'autre (non-régression).

Vocabulaire

→ Cartes
  • jeu de testsEnsemble de couples entrée/sortie attendue servant à éprouver une fonction.
  • assertionInstruction vérifiant qu'une propriété est vraie en un point du programme et interrompant l'exécution sinon.
  • exceptionÉvénement interrompant le cours normal du programme lorsqu'une erreur survient, et pouvant être rattrapé.
  • cas limiteEntrée située à la frontière du domaine (liste vide, valeur nulle, unique élément) où les erreurs se concentrent.

Sémantique d'une assertion de test

assert f(e) == s : {condition vraie⇒on continuecondition fausse⇒AssertionError (arreˆt)\texttt{assert f(e) == s}\ :\ \begin{cases} \text{condition vraie} & \Rightarrow \text{on continue} \\ \text{condition fausse} & \Rightarrow \text{AssertionError (arrêt)} \end{cases}assert f(e) == s : {condition vraiecondition fausse​⇒on continue⇒AssertionError (arreˆt)​

Une assertion compare le résultat f(e) au résultat attendu s : si l'égalité est vraie le programme poursuit, sinon il s'arrête en signalant l'échec — exactement ce qu'on veut pendant la mise au point.

Un bon jeu de tests : nominal, limite, erreur

Un bon jeu de tests : nominal, limite, erreurTableau de 3 colonnes et 3 lignes, Données: Type de cas · Exemple · Ce qu'on vérifie; nominal · racine(9) == 3 · le comportement courant; limite · racine(0) == 0 · les frontières : 0, 1, liste vide; erreur · racine(-1) lève une erreur · le refus des entrées invalides, cellule mise en évidence : limiteType de casExempleCe qu'on vérifienominalracine(9) = = 3le comportement courantlimiteracine(0) = = 0les frontières : 0, 1, listevideerreurracine(−1) lève une erreurle refus des entréesinvalides
Fig. 10Un jeu de tests couvre trois familles de cas : nominal (l'usage courant), limite (les frontières, mises en évidence : 0, 1, liste vide) et erreur (les entrées invalides, qui doivent être refusées).

Assertion qui échoue et rattrapage d'exception (try/except)

assert (hypothèse) contre try/except (rattrapage)Tableau de 3 colonnes et 2 lignes, Données: Mécanisme · Quand l'utiliser · Effet en cas de problème; assert (condition) · vérifier une hypothèse interne (mise au point) · lève AssertionError et arrête le programme; try / except · rattraper une erreur prévue à l'exécution · exécute le bloc except ; le programme continue, cellule mise en évidence : exécute le bloc except ; le programme continueMécanismeQuand l'utiliserEffet en cas deproblèmeassert (condition)vérifier une hypothèseinterne (mise au point)lève AssertionError etarrête le programmetry / exceptrattraper une erreur prévueà l'exécutionexécute le bloc except ; leprogramme continue
Fig. 11Deux mécanismes complémentaires. assert vérifie une hypothèse interne (mise au point) et arrête le programme si elle est fausse. try/except (mis en évidence) rattrape une erreur prévue à l'exécution pour que le programme continue proprement.
La lecture charge du contenu depuis YouTube (Google).Ouvrir sur YouTube ↗
Exemple corrigé

Mettre au point une fonction racine_entiere(n)

On veut racine_entiere(n) qui, pour un entier n >= 0, renvoie le plus grand entier r tel que r*r <= n (partie entière de la racine carrée). (a) Donner la spécification (pré/postcondition). (b) Écrire un jeu de tests par assertions (nominal, limite, erreur). (c) Une première version oublie le cas n = 0 et tombe en boucle infinie ; expliquer comment le jeu de tests le révèle et comment lever une exception sur une entrée négative.

  1. 01(a) Spécifier le contrat

    Précondition (appelant) : n est un entier et n >= 0. Postcondition (fonction) : le résultat r vérifie rr <= n < (r+1)(r+1), c'est-à-dire r est la partie entière de la racine de n.

  2. 02(b) Cas nominaux (assertions)

    racine_entiere(9) doit valoir 3 (3^2 = 9 <= 9 < 16), racine_entiere(10) doit valoir 3 (9 <= 10 < 16), racine_entiere(15) doit valoir 3, racine_entiere(16) doit valoir 4.

  3. 03(b) Cas limites et cas d'erreur

    Limites : racine_entiere(0) == 0 et racine_entiere(1) == 1 (frontières). Erreur : racine_entiere(-4) viole la précondition ; on attend qu'elle LÈVE une exception, ce qu'on teste avec try/except.

  4. 04(c) Le test révèle le bug, puis on corrige

    Le cas limite racine_entiere(0) fait tourner la boucle infinie de la première version : l'assertion ne renvoie jamais de résultat, le bug est localisé sur n = 0. On corrige (initialisation/condition d'arrêt) et on protège la précondition : « if n < 0: raise ValueError('n doit etre >= 0') », qu'on rattrape par try/except au point d'appel.

Résultat : La spécification fixe r tel que r^2 <= n < (r+1)^2 pour n >= 0. Le jeu de tests nominal/limite/erreur — notamment le cas limite n = 0 — fait apparaître la boucle infinie de la première version et la localise ; on corrige la condition d'arrêt, puis on lève une ValueError sur n < 0, rattrapée par un bloc try/except. Les tests conservés assurent la non-régression.

Objectif Bac

  • Objectif Bac : CONCEVOIR un jeu de tests pertinent pour une fonction donnée — proposer des cas nominaux, limites et d'erreur, et écrire les assertions correspondantes (assert f(entree) == sortie_attendue).
  • Objectif Bac : utiliser assert, raise et try/except à bon escient — savoir ce que fait une assertion qui échoue, lever une exception quand une précondition est violée, et écrire un bloc try/except qui rattrape une exception nommée.
  • Objectif Bac : proposer trois familles de cas de test — nominal, limite, erreur — et dire pour chacun ce qu'il cherche à mettre en défaut.
  • Objectif Bac : connaître la liste d'erreurs typiques que le programme inscrit noir sur blanc — problèmes de typage, effets de bord non désirés, débordements dans les tableaux, instruction conditionnelle non exhaustive, choix des inégalités, comparaisons et calculs entre flottants, mauvais nommage des variables — et savoir dire, devant un code, laquelle guette.

Erreurs fréquentes

  • Ne tester que des cas « qui marchent ». Sans cas limites (liste vide, 0, 1 élément) ni cas d'erreur, des bugs fréquents (débordement d'indice, division par zéro) passent inaperçus. Le jeu de tests doit chercher à FAIRE ÉCHOUER le programme.
  • Confondre assert et un test conditionnel de production : « assert » est un outil de mise au point/contrôle d'invariant ; il peut être désactivé globalement et ne doit pas servir à valider des données saisies par l'utilisateur. Pour cela on lève (raise) une exception et on la gère.
  • Mettre un except trop large (« except: » nu) qui rattrape TOUTES les exceptions, y compris des erreurs imprévues, et masque ainsi de vrais bugs. On rattrape l'exception PRÉCISE attendue (except ValueError:).
  • Croire que « tous les tests passent » prouve que le programme est correct. Le test montre la présence de bugs, jamais leur absence ; il complète, sans remplacer, le raisonnement sur la spécification.
  • Comparer deux flottants par `==` : `0.1 + 0.2 == 0.3` est faux en Python. On compare à une tolérance près, par exemple `abs(a - b) < 1e-9`.
  • Modifier une structure pendant qu'on la parcourt — supprimer d'une liste dans la boucle `for` qui l'énumère : le rapport du jury du Concours général NSI 2025 range cette faute parmi les erreurs de programmation majeures. Parcourez une copie, ou construisez une nouvelle structure.

§ 06

Révision active

On dispose d'une fonction moyenne(L) censée renvoyer la moyenne des éléments d'une liste de nombres. (a) Écrire un jeu de tests par assertions couvrant un cas nominal, un cas limite (liste à un seul élément) et un cas d'erreur (liste vide). (b) Proposer un comportement raisonnable sur la liste vide (lever une exception) et écrire un bloc try/except qui l'utilise sans faire planter le programme. (c) Indiquer un bug classique que ces tests permettraient de détecter.

S’entraîner sur des exercices associés50 questions sur ce thème→

Rappel actif

Rappelle-toi les points clés — puis révèle.

Sources : Annexe de l'arrêté du 19-7-2019 (NOR MENE1921247A) — programme de spécialité NSI, classe terminale (BO spécial n° 8 du 25 juillet 2019) (Ministère de l'Éducation nationale)

Vérifié · 08/2026 · Version complète via le réglage de profondeur — même endroit, mêmes ancres

Sommaire

Section -- / 06

    • 01Paradigmes de programmation : impératif, fonctionnel, objet○
    • 02Programmation orientée objet : classes, attributs, méthodes◐
    • 03Instancier et utiliser des objets en Python◐
    • 04Spécifier une fonction : préconditions, postconditions, documentation◐
    • 05Modularité : modules, bibliothèques, API et leur documentation◐
    • 06Mettre au point : jeux de tests, assertions, exceptions●

0/6 Lues

Des fiches à l'entraînement

Langages et paradigmes de programmation

Consolide ce thème avec des questions de la banque de questions.

~38
min
4
Compétences
50
questions
S'entraîner
Planifier une révision

Références et sources

Sources

Ministère de l'Éducation nationale

  • Annexe de l'arrêté du 19-7-2019 (NOR MENE1921247A) — programme de spécialité NSI, classe terminale (BO spécial n° 8 du 25 juillet 2019)

Python Software Foundation

  • Modules et paquets — documentation officielle du langage Python 3 (français)

Voir aussi

  • Histoire de l'informatiqueD’où viennent ces paradigmes, et dans quel ordre ils sont apparus.
  • Récursivité, calculabilité et décidabilitéLe paradigme fonctionnel y trouve son terrain : définir sans modifier d’état.
  • Architectures matérielles et systèmes d'exploitationCe que le langage cache : le processeur, la mémoire et le système qui exécutent réellement.

Chapitre précédent

Récursivité, calculabilité et décidabilité

Chapitre suivant

Diviser pour régner et programmation dynamique

EuraStudy·Fiches T·05·MMXXVI

Continuez avec le chapitre suivant — le parcours est conservé.