Aller au contenu

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 ?

###(DĂ©s-)Active le code aprĂšs la ligne # Tests (insensible Ă  la casse)
(Ctrl+I)
Entrer ou sortir du mode "deux colonnes"
(Ctrl+Clic pour inverser les colonnes)
Entrer ou sortir du mode "plein Ă©cran"
Tronquer ou non le feedback dans les terminaux (sortie standard & stacktrace / relancer le code pour appliquer)
Si activĂ©, le texte copiĂ© dans le terminal est joint sur une seule ligne avant d'ĂȘtre copiĂ© dans le presse-papier

Solution
  • La fonction ajout_1 ne respecte pas le paradigme fonctionnel, car nous avons un effet de bord (la variable une_liste est modifiĂ©e par la fonction ajout_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 ?

###(DĂ©s-)Active le code aprĂšs la ligne # Tests (insensible Ă  la casse)
(Ctrl+I)
Entrer ou sortir du mode "deux colonnes"
(Ctrl+Clic pour inverser les colonnes)
Entrer ou sortir du mode "plein Ă©cran"
Tronquer ou non le feedback dans les terminaux (sortie standard & stacktrace / relancer le code pour appliquer)
Si activĂ©, le texte copiĂ© dans le terminal est joint sur une seule ligne avant d'ĂȘtre copiĂ© dans le presse-papier

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 ?

###(DĂ©s-)Active le code aprĂšs la ligne # Tests (insensible Ă  la casse)
(Ctrl+I)
Entrer ou sortir du mode "deux colonnes"
(Ctrl+Clic pour inverser les colonnes)
Entrer ou sortir du mode "plein Ă©cran"
Tronquer ou non le feedback dans les terminaux (sortie standard & stacktrace / relancer le code pour appliquer)
Si activĂ©, le texte copiĂ© dans le terminal est joint sur une seule ligne avant d'ĂȘtre copiĂ© dans le presse-papier

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 :

🐍 Script Python
def double(x):
    return 2 * x

Peut ĂȘtre remplacĂ©e par

🐍 Script Python
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 :

🐍 Script Python
double = lambda x: 2 * x
tester ci-dessous :

###(DĂ©s-)Active le code aprĂšs la ligne # Tests (insensible Ă  la casse)
(Ctrl+I)
Entrer ou sortir du mode "deux colonnes"
(Ctrl+Clic pour inverser les colonnes)
Entrer ou sortir du mode "plein Ă©cran"
Tronquer ou non le feedback dans les terminaux (sortie standard & stacktrace / relancer le code pour appliquer)
Si activĂ©, le texte copiĂ© dans le terminal est joint sur une seule ligne avant d'ĂȘtre copiĂ© dans le presse-papier

Deux fonctions en paramĂštres

Exécuter le code ci-dessous, observer le résultat.

Vous pouvez expérimenter en mettant vos propres fonctions.

###(DĂ©s-)Active le code aprĂšs la ligne # Tests (insensible Ă  la casse)
(Ctrl+I)
Entrer ou sortir du mode "deux colonnes"
(Ctrl+Clic pour inverser les colonnes)
Entrer ou sortir du mode "plein Ă©cran"
Tronquer ou non le feedback dans les terminaux (sortie standard & stacktrace / relancer le code pour appliquer)
Si activĂ©, le texte copiĂ© dans le terminal est joint sur une seule ligne avant d'ĂȘtre copiĂ© dans le presse-papier

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

###(DĂ©s-)Active le code aprĂšs la ligne # Tests (insensible Ă  la casse)
(Ctrl+I)
Entrer ou sortir du mode "deux colonnes"
(Ctrl+Clic pour inverser les colonnes)
Entrer ou sortir du mode "plein Ă©cran"
Tronquer ou non le feedback dans les terminaux (sortie standard & stacktrace / relancer le code pour appliquer)
Si activĂ©, le texte copiĂ© dans le terminal est joint sur une seule ligne avant d'ĂȘtre copiĂ© dans le presse-papier

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):

Recopier
>>> f1 = affine(3, -2)
>>> f1(5)
>>> affine(-1, 4)(3)
###(DĂ©s-)Active le code aprĂšs la ligne # Tests (insensible Ă  la casse)
(Ctrl+I)
Entrer ou sortir du mode "deux colonnes"
(Ctrl+Clic pour inverser les colonnes)
Entrer ou sortir du mode "plein Ă©cran"
Tronquer ou non le feedback dans les terminaux (sortie standard & stacktrace / relancer le code pour appliquer)
Si activĂ©, le texte copiĂ© dans le terminal est joint sur une seule ligne avant d'ĂȘtre copiĂ© dans le presse-papier

Qu'obtenez-vous ?

Solution
🐍 Console Python
>>> 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\).

Exemples d'utilisation
>>> 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

###(DĂ©s-)Active le code aprĂšs la ligne # Tests (insensible Ă  la casse)
(Ctrl+I)
Entrer ou sortir du mode "deux colonnes"
(Ctrl+Clic pour inverser les colonnes)
Entrer ou sortir du mode "plein Ă©cran"
Tronquer ou non le feedback dans les terminaux (sortie standard & stacktrace / relancer le code pour appliquer)
Si activĂ©, le texte copiĂ© dans le terminal est joint sur une seule ligne avant d'ĂȘtre copiĂ© dans le presse-papier
Évaluations restantes : 5/5

.128013ldy1,*k/eib:mcaP+r =ofgt2sSh)(punxv050c0j0y0p0k0b0A0t0o0b0p0A0A0u010y0k0F010406050A0G0n0n0p0s0d040B0v0b0G0!0v0H050i0+0-0/0;0)0F0405140}170i140)0c0k0J0S0U0W0Y0C0k0x0C0b1l0C0y0%050N0l0b0j1g0V0X011k1m1o1m0y1u1w1s0y0s150y0C0S0@0A0F0p0H0Y0z011y1i010w0P0j0H0p0n0j1s1R1T1Y1A1#1w1(1*0%0a0t0q0s0v0F0v0A0k0`0H0t0L1P0s0s0j0o220}1-0H150i1N2f1K1M1L1t0c1/0Y1o0H1%1 1s1d1f0T1z2p0k2r0H0v2v1s0F28152d2f2J0*1S232x1Z2C0s0.0b0%0e2c2N0(2M1.2P1A2R2T0%0z2X1T2f2G0j2f2v2i0c1M2n2$0Y0o2D1+152=162H2!2e2,342|0L2I2N2o010h0%0L0w35040t333b0H0w0%1K2A0v1*3h3k2`010$040E3t2d3l0%0p3A3a3v3x0f3h3j3B3v0H0%0l3F2#1h1A3I3K3u3T0Y3O040o3R2O3Y3w0%0D0m3h060t3:3L3G3)3d04280y0G0s0|0~2Y3=3S2y3c0%0U0n0l0c3E3 2-413(433!0I3%3b3x3-4b2e4d3C044a2L3M3)0v0%0g4i3N0%4h4m39421Z4v044x4C3X4f4A3W4t434G0r4N3?4L043Q4J4O4F4w4y3)4g4S4E1A4Q4(4e2Q0%3$4C0)0i372:18320i302g2@0}2j4 0p1v4^4{1e2Z4{0M0O0Q04.

###(DĂ©s-)Active le code aprĂšs la ligne # Tests (insensible Ă  la casse)
(Ctrl+I)
Entrer ou sortir du mode "deux colonnes"
(Ctrl+Clic pour inverser les colonnes)
Entrer ou sortir du mode "plein Ă©cran"
Tronquer ou non le feedback dans les terminaux (sortie standard & stacktrace / relancer le code pour appliquer)
Si activĂ©, le texte copiĂ© dans le terminal est joint sur une seule ligne avant d'ĂȘtre copiĂ© dans le presse-papier
Évaluations restantes : 5/5

.128013ldy1,*k/eib:mcaP+r =ofgt2sShpunxv050c0j0y0p0k0b0A0t0o0b0p0A0A0u010y0k0D010406050A0E0n0n0p0s0d040B0v0b0E0Y0v0F050i0)0+0-0/0%0D0405120{150i120%0c0k0H0Q0S0U0W0C0k0x0C0b1j0C0y0#050L0l0b0j1e0T0V011i1k1m1k0y1s1u1q0y0s130y0C0Q0=0A0D0p0F0W0z011w1g010w0N0j0F0p0n0j1q1P1R1W1y1Z1u1$1(0#0a0t0q0s0v0D0v0A0k0^0F0t0J1N0s0s0j0o200{1+0F130i1L2d1I1K1J1r0c1-0W1m0F1#1}1q1b1d0R1x2n0k2p0F0v2t1q0D26132b2d2H0(1Q212v1X2A0s0,0b0#0e2a2L2d2E0j2d2t2g0c1K2l2N1y0o2B1)132#142F2K1R2I2W052,0J2G2L2m010F0#1I2y0v1(2V2@0t2?2M1f1y0v0#0u372c392b2 0h0#0S0n0l0c0p3h043j2~2*0W31043s0|2_3k3x010!040f3t3v1,3F3z0l3t3a2 3H3J3C383R3N0#0o3Q3E3c0W3H0m3K3X3%013m043o3q3B2H3L3b2w300#0G3#3w3-3)3+3$3`3z3?3D3 3`3e040g3~3M3-3z3}3V2c3,490#4c4i2}4e443|42481X4a0r4t4q2O0#3P4o4k4v4m4d3_4A044h3@4E3d0#4x4o3^2 3z3!4o0%0i2{2Z162=0i2:2e2%0{2h4+0p1t4!4%1c0$0{0J0L0N0A04.

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.

###(DĂ©s-)Active le code aprĂšs la ligne # Tests (insensible Ă  la casse)
(Ctrl+I)
Entrer ou sortir du mode "deux colonnes"
(Ctrl+Clic pour inverser les colonnes)
Entrer ou sortir du mode "plein Ă©cran"
Tronquer ou non le feedback dans les terminaux (sortie standard & stacktrace / relancer le code pour appliquer)
Si activĂ©, le texte copiĂ© dans le terminal est joint sur une seule ligne avant d'ĂȘtre copiĂ© dans le presse-papier

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.

###(DĂ©s-)Active le code aprĂšs la ligne # Tests (insensible Ă  la casse)
(Ctrl+I)
Entrer ou sortir du mode "deux colonnes"
(Ctrl+Clic pour inverser les colonnes)
Entrer ou sortir du mode "plein Ă©cran"
Tronquer ou non le feedback dans les terminaux (sortie standard & stacktrace / relancer le code pour appliquer)
Si activĂ©, le texte copiĂ© dans le terminal est joint sur une seule ligne avant d'ĂȘtre copiĂ© dans le presse-papier

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.

###(DĂ©s-)Active le code aprĂšs la ligne # Tests (insensible Ă  la casse)
(Ctrl+I)
Entrer ou sortir du mode "deux colonnes"
(Ctrl+Clic pour inverser les colonnes)
Entrer ou sortir du mode "plein Ă©cran"
Tronquer ou non le feedback dans les terminaux (sortie standard & stacktrace / relancer le code pour appliquer)
Si activĂ©, le texte copiĂ© dans le terminal est joint sur une seule ligne avant d'ĂȘtre copiĂ© dans le presse-papier

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.

###(DĂ©s-)Active le code aprĂšs la ligne # Tests (insensible Ă  la casse)
(Ctrl+I)
Entrer ou sortir du mode "deux colonnes"
(Ctrl+Clic pour inverser les colonnes)
Entrer ou sortir du mode "plein Ă©cran"
Tronquer ou non le feedback dans les terminaux (sortie standard & stacktrace / relancer le code pour appliquer)
Si activĂ©, le texte copiĂ© dans le terminal est joint sur une seule ligne avant d'ĂȘtre copiĂ© dans le presse-papier

CrĂ©dits⚓

Frédéric Junier, Eduscol,