Open In Colab

Paradigme impératif, Python les bases Pascal Fares (c) Cnam Liban

Programmation impérative : introduction, impératif?

Objectifs

  • Comprendre les principes de la programmation impérative
  • Algorithmique : types primitifs, instructions, structures de contrôle
  • Méthode des raffinages.
  • Structuration des données : tableaux, enregistrements, types énumérés
  • Structuration des instructions : sous-programmes et modules

Variables, valeurs

Une des fonctionnalités essentielle d'un langage de programmation impératif est la manipulation des variables et les faire évoluer jusqu'à obtenir le résultat souhaité à partir d’une situation initiale.

Une variable est un nom qui fait référence à une valeur. je schématise souvent par {nom: valeur}

pour donner une valeur à une variable => l’affectation (change l’état, car change la valeur)

Exemple:

In [1]:
x = 3 
message = "Un long message texte"
un_autre_message = 'Aussi un texte'
pi = 3.141592653589793
In [ ]:
globals()

État

J'applelerais l'état d'un programme, l'ensemble des variables et de leur valeur

dans l'exemple précédent j'aurais:

{x: 3, message: "Un long message texte", un_autre_message: "aussi un texte", pi: 3.141592653589793}

Nous avons vu dans l'introduction, notion de calculabilité: qu'un algorithme ou le programme (traduction de l'algorithme dans un language de programmation) permettent de transformer:

  • une situation (état) initiale,
  • au moyen d'une séquence d'instructions ,
  • en une situation (état) final qui est le résultat souhaité

Premier exemple : résoudre équation du premier degré ax+b=0

Programme premier_degre
Variables
       a : entier
       b: entier
       r:  réel
Debut
      -- saisir les données
      Ecrire (“Donner a et b”)
      Lire(a)
      Lire(b)
      -- Calculer les réponses
      -- réponse = -b/a a condition que a soit non nul (0)
     r= -b/a
      Ecrire (“La réponse est “, r)
     -- ce programme n’est pas tout a fait correct
Fin

Executer sur papier le programme précédent

remarques

-- est un commentaire

Le reste est-il suffisament claire?

A-t-on besoin de beaucoup plus d'explications?

Sémantique

Sémantique ou modèle de calcul: C’est ce qui donne le sens du programme (explique son comportement)

L’état du programme:

  • La valeur des variables déclarées dans le programme (une zone de la mémoire)
  • Le compteur ordinal : le numéro de la prochaine instruction à exécuter

Lancement du programme :

  • Au début de l’exécution, les variables ont une valeur indéterminée.
  • Le compteur ordinal indique la première instruction du programme principal

Exécution : Exécution de l’instruction référencée par le compteur ordinal et mise à jour du compteur ordinal (en général l’instruction suivante : séquence).

Principe du paradigme impératif : instruction / expression

Un programme est une séquence d’instructions qui modifient son état (cad les valeurs des variable déclarés). => l’affectation est la seule instruction qui modifie l’état!

x = a+b est une instruction elle modifie x

a+b seule n’est pas une instruction rien ne se passe (du point de vue état): du point de vue du programme qu’on écrit.

Bien sure au niveaux machine il se passe des choses et a+b est un programme pour la machine elle même mais pas pour le programmeur.

on dit que a+b est une expression elle produit un résultat, ne modifie en elle même aucun état.

Changement d'un état, pour une instruction $$e_i \xrightarrow{\text{instruction}} e_j$$

Un programme impératif par de l'état initial $e_{init}$ et se termine dans un etat final $e_{fin}$ suite à l'exucution d'une séquence d'instructions

$$e_{init} \xrightarrow{\text{instructions}} ... \xrightarrow{\text{instructions}} e_{fin}$$
In [ ]:
#Exemple
x = 2
y = 2*x
In [ ]:
x
Out[ ]:
2
In [ ]:
y
Out[ ]:
4
In [ ]:
 
$$\phi \xrightarrow{\text{x=2}} {x:2} \xrightarrow{\text{y=2*x}} {x:2, y:4}$$

Les défis

Définir des outils de structuration des programmes pour permettre la conception, l’écriture et la maintenance (évolutive et corrective) de programme de grande taille :

  • Structures de contrôle (conditionnelle et répétition)
  • Types de données : organiser les données.
  • Sous-programmes : procédures et fonctions (organiser les instructions)
  • Modules et bibliothèques (organisation les sous-programmes et les types)
  • Mais aussi : raisonner sur le programme (typage, flot de contrôle, assertions, preuve...), tests (fonctionnels, structurels, de performance), documentation, etc.

Comment trouver une solution : Le raffinage

Décomposer le problème posé en sous-problèmes qui seront à leur tour décomposés jusqu’à obtenir des problèmes élémentaires (i.e. compréhensible du processeur).

Ici un problèmes est élémentaire s’il correspond à une instruction ou une expression du langage algorithme.

Au debut : Comprendre le problème

Pour avoir une chance de trouver la solution (un programme qui répond à la demande), il faut bien comprendre le problème posé (la demande)

Moyens :

  • Reformuler le problème en rédigeant la demande.
  • Lister des « exemples ou cas d’utilisation » du programme. Il s’agit de préciser :
    • les données en entrées ;
    • et les résultats attendus.

Remarque : Les exemples d’utilisation donneront les jeux de test fonctionnels qui permettront de tester le programme.

Le développement dirigé par les tests (TDD) préconise d'écrire les tests avant le programme lui même

Revenons a notre exemple : une equation du premier degré

Problème (demande du client): résoudre l’équation du premier degré où on devra saisir les coéficients de l'équiation

Premier raffinage : mieux comprendre le problème en posant des questions aux spécialiste du domaine.

R0 : résoudre l’équation du premier degré sous la forme ax+b=0, a et b sont saisies par l'utilisateur

donner quelques exemples: cas d’utilisation ou exemple d’utilisation : jeux de test

  • [ ] a=1,b=0 => réponse 0
  • [ ] a=1,b=1 => réponse -1
  • [ ] a=0,b!=0 => erreur pas de solution
  • [ ] a=0,b=0 => infinité de solution

Identifier une solution informelle

  • Identifier une manière de résoudre le problème.
  • Il s’agit d’avoir l’idée, l’intuition de comment traiter le problème.
  • Comment trouver l’idée ? C’est le point difficile ! c'est l'éxpérience, c'est le travail, c'est les exemples, ....

Par exemple : Pour calculer la solution du premier degré , ici la solution est triviale (x = -b/a) à condition de penser à tous les cas particuliers et comment les traiter et à quel moment

Remarque : On peut vérifier son idée sur les exemples d’utilisation identifiés.

Continuer à raffiner

-- R0 : résoudre l’équation du premier degré sous la forme ax+b=0

R01 : Lire les données a,b

R02 : calculer -b/a en respectant les contrainte

R03 : afficher le résultat

Raffinons R02

-- R02 : calculer -b/a en respectant les contraintes : choisir la solution en fonctions des valeur en entrée a et b

R021. Si a!=0 solution est -b/a

R022. si a et b = 0 une infinité de solution

R023. si a=0 et b!=0 pas de solution

Tout ceci commence à prendre forme

In [ ]:
# l'algorithme directement en pseudo python (je reviendrais sur la syntaxe, pour le moment consider que c'est du pseudo code)
# Le raffinage R02
def f_premier_degre(a,b):
  '''
  a: coéficient a
  b: coéficient b
  '''
  if a != 0: return (-b/a)
  if a == b == 0: return "Infinité de solutions"
  if a == 0 and b !=0: return "Pas de solution"
In [ ]:
# Le programme principal (le début), Le raffinage R0
def premier_degre():
  '''
  résourdre l'equation du premier degré sous la forme
  a*x + b = 0
  '''
  print("Saisir a et b les coéficient de l'équiation a*x+b=0")
  a = input("Donner le coéficient a :")
  b = input("Donner le coéficient b :")
  print(f_premier_degre(a,b))
In [ ]:
help(premier_degre)
Help on function premier_degre in module __main__:

premier_degre()
    résourdre l'equation du premier degré sous la forme
    a*x + b = 0

In [ ]:
premier_degre()
In [ ]:
# Le programme principal (le début), Le raffinage R0
def premier_degre():
  '''
  résourdre l'equation du premier degré sous la forme
  a*x + b = 0
  '''
  a = input("Donner le coéficient a :")
  b = input("Donner le coéficient b :")
  print(f_premier_degre(int(a),int(b)))
In [ ]:
premier_degre()
Donner le coéficient a :10
Donner le coéficient b :20
-2.0
In [ ]:
# le vraie travail est fait dans f_premier_degre, testons..
assert f_premier_degre(0,0) == "Infinité de solutions", "quand a et b=0 on doit avoir infomnité de solution"
assert f_premier_degre(0,1) == "Pas de solution", "quand a=0 et b!=0 on doit avoir pas de solution"
assert f_premier_degre(1,1) == -1, f"Devrait être -1/1 le résultat était {f_premier_degre(1,1)}"
assert f_premier_degre(1,-2) == 2, f"Devrait être 2/1 le résultat était {f_premier_degre(1,-2)}"