EuraStudy
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 lecture4 compétencesVérifié · 08/2026
Profondeur de lecture : Approfondi
Taille du texte : Standard · Interligne : Compact
Toujours charger les médias : désactivé
6 sections25 points clés7 formules30 pièges signalés
Trois paradigmes pour un même problème : sommer une liste
Vocabulaire
→ CartesLe style FONCTIONNEL : une définition récursive, sans variable mutable
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
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()) ».
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.
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.
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().
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.
Erreurs fréquentes
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)
La « carte d'identité » d'une classe : attributs et méthodes
Vocabulaire
→ CartesInstancier : du moule (classe) à l'exemplaire (objet)
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
É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.
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.
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.
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).
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.
Erreurs fréquentes
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)
Un moule, plusieurs instances : des objets distincts
Vocabulaire
→ CartesAppeler une méthode : la liaison automatique de self
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))
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
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 ?
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.
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.
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.
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.
Erreurs fréquentes
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)
Le contrat d'une fonction : précondition, fonction, postcondition
Vocabulaire
→ CartesLe contrat d'une fonction : précondition → fonction → postcondition
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.
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.
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).
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).
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().
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.
Erreurs fréquentes
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)
Un programme, ses modules et leur documentation
Vocabulaire
→ CartesImporter, c'est créer un espace de noms
`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 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é ?
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.
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
`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.
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.
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.
Erreurs fréquentes
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)
Le cycle de mise au point : spécifier, coder, tester, corriger
Vocabulaire
→ CartesSémantique d'une assertion de test
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
Assertion qui échoue et rattrapage d'exception (try/except)
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.
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.
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.
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.
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.
Erreurs fréquentes
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/2026Version complète via le réglage de profondeur — même endroit, mêmes ancres
Références et sources
Ministère de l'Éducation nationale
Python Software Foundation
Voir aussi