Paradigmes de programmation
I. Les diffĂ©rents paradigmesâïž
Il existe plusieurs façons de rĂ©soudre un problĂšme Ă l'aide d'un langage de programmation. Une façon d'approcher un problĂšme correspond Ă un style de programmation qu'on qualifie de paradigme. La plupart des langages de programmation gĂ©nĂ©ralistes modernes permettent d'utiliser plusieurs paradigmes et de les mĂ©langer dans un mĂȘme programme. On parle de langages multi-paradigmes.
On va présenter quelques paradigmes parmi les plus répandus.
đœ Paradigme impĂ©ratifâïž
Des notions familiĂšres
La programmation impérative repose sur des notions qui vous sont familiÚres :
- la séquence d'instructions (les instructions d'un programme s'exécutent l'une aprÚs l'autre)
- l'affectation (on attribue une valeur Ă une variable, par exemple : a = 5)
- l'instruction conditionnelle (if / else)
- la boucle (while et for)
Le paradigme impératif
Dans le paradigme impératif, les données sont stockées dans des variables et le programme s'organise comme une séquence d'instructions qui vont modifier l'état du programme (données en mémoire et position dans le code source) depuis un état initial jusqu'à un état final correspondant à la solution du problÚme.
Quelques traits principaux du paradigme impératif
- La valeur d'une variable peut évoluer au cours de l'exécution : on parle de structure mutable
- Une instruction effectue une action pouvant modifier l'Ă©tat du programme : ce peut ĂȘtre une affectation de variable (modification des donnĂ©es en mĂ©moire), une structure de contrĂŽle (test ou boucle qui modifie la position dans le code source)
- Un programme est une séquence d'instructions.
- Les unitĂ©s de code rĂ©utilisables peuvent ĂȘtre stockĂ©es dans des fonctions ce qui facilite la lisibilitĂ©, la maintenance, la rĂ©utilisabilitĂ©. On parle alors de programmation structurĂ©e.
đœ Paradigme objetâïž
En bref
- Le paradigme objet organise les donnĂ©es en une collection d'objets dont l'Ă©tat interne (stockĂ© dans des attributs) peut ĂȘtre modifiĂ© Ă l'aide de mĂ©thodes (des fonctions).
- Les objets sont instanciés à partir de classes qui étendent la notion de type du paradigme impératif.
- Un programme se présente comme une séquence d'interactions entre objets.
- Les objets sont souvent des structures mutables et le paradigme objet est une sorte de surcouche du paradigme impératif dont il reprend les concepts de variable, de séquence et de structure contrÎle.
- La plupart des langages modernes comme Python, supportent ces deux paradigmes.
đĄ A noter
Le paradigme objet permet de représenter des structures de données complexes en garantissant une propriété d'encapsulation
- l'utilisateur ne peut manipuler la structure qu'Ă travers une interface publique de façon indĂ©pendante de l'implĂ©mentation qui reste cachĂ©e et peut ĂȘtre modifiĂ©e sans impact sur le code client
- l'encapsulation facilite le travail en équipe sur de gros projets en permettant le découpage d'un programme en modules indépendants
đœ Paradigme fonctionnelâïž
đ PrĂ©sentation
Le paradigme fonctionnel organise un programme comme un enchaßnement d'évaluations de fonctions, chaque résultat produit en sortie d'une fonction étant pris en entrée de la fonction suivante.
Caractéristiques
Il en découle un certain nombre de traits spécifiques au paradigme fonctionnel :
- La valeur d'une variable ne change pas. Les structures de donnĂ©es sont immuables c'est-Ă -dire qu'elles ne peuvent ĂȘtre modifiĂ©es aprĂšs leur crĂ©ation. Cela permet d'empĂȘcher les effets de bord.
- Il n'existe donc pas d'instructions comme l'affectation qui peuvent modifier l'Ă©tat du programme. Le calcul repose sur l'Ă©valuation d'expressions, qui ont une valeur, et de fonctions, qui associent Ă une valeur, une autre valeur.
- Les fonctions sont des valeurs commes autres. Une fonction peut ĂȘtre argument d'une autre fonction, valeur de retour d'une autre fonction, stockĂ©e dans une structure de donnĂ©es.
- Une fonction peut donc s'appliquer à d'autres fonctions, on parle de fonction d'ordre supérieur : les analogies mathématiques sont la composition de fonction, la dérivation, l'intégration ...
- Les structures d'itération commes les boucles du paradigme impératif sont remplacées par la récursion.
- Les fonctions sont des fonctions pures c'est-Ă -dire qu'elles ne provoquent pas d'effets de bord lors de leur Ă©valuation et que pour des entrĂ©es fixĂ©es, elles donnent toujours le mĂȘme rĂ©sultat en sortie. Cette propriĂ©tĂ© garantit la transparence rĂ©fĂ©rentielle c'est-Ă -dire que tout appel de fonction peut ĂȘtre remplacĂ© par la valeur de son Ă©valuation sans modifier le programme. Ceci ne serait pas garanti avec une fonction impure dont l'Ă©valuation pourrait s'accompagner d'effets de bord en plus du calcul du rĂ©sultat.
II. Le paradigme fonctionnelâïž
1. Exemple 1 : effet de bordâïž
Exemple 1
Exécuter le code ci-dessous. Que se passe-t-il ?
Solution
- La fonction
ajout_1
ne respecte pas le paradigme fonctionnel, car nous avons un effet de bord (la variableune_liste
est modifiée par la fonctionajout_1
). - La fonction
ajout_2
ne modifie aucune variable, elle crée un nouveau tableau. Elle ne produit pas d'effet de bord.
2. Exemple 2 : Transparence rĂ©fĂ©rentielleâïž
Exemple 2
Exécuter le code ci-dessous. Que se passe-t-il ?
# Tests
(insensible Ă la casse)(Ctrl+I)
(Ctrl+Clic pour inverser les colonnes)
Solution
Les langages fonctionnels ont comme autre propriété la transparence référentielle. Ce terme recouvre le principe simple selon lequel le résultat du programme ne change pas si on remplace une expression par une expression de valeur égale. Ce principe est violé dans le cas de procédures à effets de bord puisqu'une telle procédure, ne dépendant pas uniquement de ses arguments d'entrée, ne se comporte pas forcément de façon identique à deux instants donnés du programme.
Ici, la fonction incremente_1
ne respecte donc pas cette proporiété de transparence référentielle. Elle ne respecte pas le
paradigme fonctionnel
Les fonctions puresâïž
Les fonctions pures
- Une fonction pure est une fonction qui ne modifie rien ; elle ne fait que renvoyer des valeurs en fonction de ses paramĂštres.
- Les modifications quâune fonction peut effectuer sur lâĂ©tat du systĂšme sont appelĂ©es effets de bord. Un affichage Ă lâĂ©cran est un exemple dâeffet de bord.
Fonctions d'ordre supĂ©rieurâïž
Des fonctions passées en paramÚtres
Les fonctions sont des objets de premiĂšre classe, ce qui signifie qu'elles sont manipulables aussi simplement que les types de base.
đ Une fonction peut prendre des fonctions comme paramĂštres ou renvoyer une fonction comme rĂ©sultat.
Exemple 3
Exécuter le code ci-dessous. Que se passe-t-il ?
# Tests
(insensible Ă la casse)(Ctrl+I)
(Ctrl+Clic pour inverser les colonnes)
Solution
La fonction sorted
est une fonction d'ordre supérieur, qui prend en paramÚtre une fonction, comme ici clef_note
ou clef_nom
Fonctions anonymes et opérateur lambda
On peut Ă©crire le mĂȘme code de façon plus concise, en utilisant des fonctions anonymes, grĂące Ă l'opĂ©rateur lambda
.
Par exemple la fonction :
def double(x):
return 2 * x
Peut ĂȘtre remplacĂ©e par
lambda x: 2 * x
On a "perdu" le nom de cette fonction, qui parfois n'est pas utile (d'oĂč le nom de fonction anonyme)
Si on le désire, on peut écrire :
double = lambda x: 2 * x
# Tests
(insensible Ă la casse)(Ctrl+I)
(Ctrl+Clic pour inverser les colonnes)
Deux fonctions en paramĂštres
Exécuter le code ci-dessous, observer le résultat.
Vous pouvez expérimenter en mettant vos propres fonctions.
# Tests
(insensible Ă la casse)(Ctrl+I)
(Ctrl+Clic pour inverser les colonnes)
Renvoyer une fonctionâïž
Une fonction qui prend deux fonctions en pramĂštres et renvoie une fonction
Dans l'exemple précédant le résultat renvoyé était un réel, calculé à l'aide des paramÚtres (f, g, x)
.
Nous allons maintenant créer une fonction qui prend en paramÚtres seulement des fonctions, et renvoie une fonction.
Tester ci-dessous
# Tests
(insensible Ă la casse)(Ctrl+I)
(Ctrl+Clic pour inverser les colonnes)
Solution
k
est une fonction, et on peut l'appeler avec n'importe quel nombre en paramĂštre.
les fonctions affines
On peut également définir une fonction qui renvoie une fonction. La fonction affine
prend en paramĂštres deux nombres
a
et b
et renvoie la fonction \(x \mapsto ax + b\).
Exécuter le code ci-dessous, puis recopier ligne par ligne dans la console (exécuter chaque ligne):
>>> f1 = affine(3, -2)
>>> f1(5)
>>> affine(-1, 4)(3)
# Tests
(insensible Ă la casse)(Ctrl+I)
(Ctrl+Clic pour inverser les colonnes)
Qu'obtenez-vous ?
Solution
>>> f1 = affine(3, -2)
>>> f1(5)
13
>>> affine(-1, 4)(3)
1
f1
est la fonction affine définie par : pour tout \(x\) on a \(f1(x)=3x-2\)
\(f1(5)=15-2=13\)
On a ensuite créé la fonction affine définie par : pour tout \(x\) on a \(f(x)=-x+4\) .
On a ensuite déterminé l'image de 1 par cette fonction : \(-3+4=1\)
Exercice sur les fonctions du second degré
Ăcrire le code de la fonction trinome
qui prend en paramĂštre 3 nombres a
, b
et c
, avec a
non nul, et qui renvoie la fonction \(x \mapsto ax^2+ bx +c\).
>>> f = trinome(1, 1, 1) # x^2+x+1
>>> f(2) # 2^2+2+1 = 7
7
>>> f(0) # 0^2+0+1 = 1
1
>>> trinome(3, -1, 2)(6) # 3*6^2-6+2 = 104
104
# Tests
(insensible Ă la casse)(Ctrl+I)
(Ctrl+Clic pour inverser les colonnes)
# Tests
(insensible Ă la casse)(Ctrl+I)
(Ctrl+Clic pour inverser les colonnes)
III. Exemples de fonctions d'ordre supérieurs map
et filter
en pythonâïž
La fonction map
La fonction map est une fonction qui permet dâappliquer un traitement Ă tous les Ă©lĂ©ments dâun itĂ©rable. Cette fonction ne modifie pas l'objet' de dĂ©part : elle renvoie un objet (itĂ©rable) encapsulant le rĂ©sultat (le rĂ©sultat nâest pas construit Ă lâappel) ; les valeurs sont calculĂ©es lorsquâelles sont requises ; câest une mise en Ćuvre du principe dâĂ©valuation paresseuse. Le traitement est bien sĂ»r spĂ©cifiĂ© via une fonction.
Appliquer une fonction à chaque élément d'un itérable - 1
Exécuter le code ci-dessous, observer le résultat.
# Tests
(insensible Ă la casse)(Ctrl+I)
(Ctrl+Clic pour inverser les colonnes)
Appliquer une fonction à chaque élément d'un itérable - 2
On aurait pu utiliser une fonction anonyme. Exécuter le code ci-dessous, observer le résultat.
# Tests
(insensible Ă la casse)(Ctrl+I)
(Ctrl+Clic pour inverser les colonnes)
La fonction filter
La fonction filter
est un autre exemple de fonction dâordre supĂ©rieur sâappliquant Ă
des objets itérables. Elle prend en premier paramÚtre une fonction à valeur booléenne appelée
filtre, et un objet itérable en deuxiÚme paramÚtre. En résultat, elle renvoie un iterable ne
contenant que les valeurs de la liste pour lesquels le filtre renvoie la valeur True
.
Appliquer un filtre à chaque élément d'un itérable - 1
Exécuter le code ci-dessous, observer le résultat.
# Tests
(insensible Ă la casse)(Ctrl+I)
(Ctrl+Clic pour inverser les colonnes)
Appliquer un filtre à chaque élément d'un itérable - 2
On aurait pu utiliser une fonction anonyme. Exécuter le code ci-dessous, observer le résultat.
# Tests
(insensible Ă la casse)(Ctrl+I)
(Ctrl+Clic pour inverser les colonnes)
CrĂ©ditsâïž
Frédéric Junier, Eduscol,
# Tests
(insensible Ă la casse)(Ctrl+I)
(Ctrl+Clic pour inverser les colonnes)