Reprenons le projet Peinture du cours Première Notion.
Rappelons que ce programme permet de calculer la surface à peindre d'une pièce rectangulaire connaissant les dimensions de la pièce (longueur, largeur), le nombre de fenêtres et le nombres de portes.
Cet exemple nous avait justement servi à illustrer le principe du découpage d'un traitement en sous-traitements. Lorsqu'un calcul est trop complexe, on a intérêt à le découper en plusieurs calculs intermédiaires et sauvegarder les résultats intermédiaires dans des variables.
Cela nous avait donné le code suivant.
Nous avons ici un exemple de code qui peut très facilement se réécrire à l'aide de sous-programmes de la manière suivante (la partie déclaration des sous-programmes a été ommise en un premier temps pour ne pas surcharger l'exemple) :
# Constantes LARGEUR_FENETRE = 1.4 HAUTEUR_FENETRE = 1.2 LARGEUR_PORTE = 0.9 HAUTEUR_PORTE = 2.1 HAUTEUR_MUR = 2.5 # Declaration des sous-programmes ...... # Lecture des donnees LargeurPiece = float (input ("Largeur de la piece : ")) LongueurPiece = float (input ("Longueur de la piece : ")) NFenetre = int (input ("Nombre de fenetres : ")) NPorte = int (input("Nombre de portes : ")) # Traitement des donnees CalculerSurfaceDesMurs () CalculerSurfaceDesFenetres () CalculerSurfaceDesPortes () CalculerSurface_A_Peindre () # Affichage du resultat print ("Surface a peindre : "+ str(SurfacePeinture))
Les instructions en blanc sont des appels de sous-programme.
Les instructions permettant de calculer les surfaces (murs, fenêtres, portes, surface à peindre) sont à présent contenues dans des sous-programmes situés juste après la définition des constantes. Voici leur code:
.... # Declaration des sous-programmes def CalculerSurfaceDesMurs () : global SurfaceDesMurs SurfaceDesMurs = \ 2 * (LargeurPiece * HAUTEUR_MUR + \ LongueurPiece * HAUTEUR_MUR) def CalculerSurfaceDesFenetres () : global SurfaceDesFenetres SurfaceDesFenetres = \ NFenetre * LARGEUR_FENETRE * HAUTEUR_FENETRE def CalculerSurfaceDesPortes () : global SurfaceDesPortes SurfaceDesPortes = \ NPorte * LARGEUR_PORTE * HAUTEUR_PORTE def CalculerSurface_A_Peindre () : global SurfacePeinture SurfacePeinture = \ SurfaceDesMurs - SurfaceDesFenetres - SurfaceDesPortes # Lecture des donnees ...
Nous avons ici quatre déclaration de sous-programmes.
De manière générale, une déclaration de sous-programme s'écrit de la manière suivante:
def Nom du sous-programme ( liste des paramètres ) : Bloc d'instructions
La première ligne de la déclaration s'appelle l'entête. Le bloc d'instruction situé juste après l'entête est le corps du sous-programme.
Précisons également que les quatre exemples de sous-programmes présentés ici sont très particuliers:
Avec les sous-programmes, les instructions d'un fichier source python peuvent être classées en deux catégories:
Toute instruction python appartient donc soit au programme principal, soit à un sous-programme.
Un sous-programme ne s'éxécute que lorsqu'il est appelé. Pour une procédure, cela signifie qu'il existe quelque part dans le code une instruction d'appel de ce sous-programme. Dans notre exemple, ce sont les quatre instructions en blanc dans le corps du programme principal.
Voyons un peu comment s'exécute le programme.
L'exécution d'un programme Python démarre toujours à la première instruction du programme principal.
Dans notre exemple, ce sera l'instruction:
LARGEUR_FENETRE = 1.4
Nous sommes dans la définition des constantes.
Après avoir exécuté les quatres affectations définissant les quatre constantes suivantes, l'interpréteur rencontre une déclaration de sous-programme.
def CalculerSurfaceDesMurs () : global SurfaceDesMurs SurfaceDesMurs = \ 2 * (LargeurPiece * HAUTEUR_MUR + \ LongueurPiece * HAUTEUR_MUR)
A ce stade les instructions contenues dans le sous-programme ne sont pas exécutées. L'interpréteur se contente d'enregistrer la définition du sous-programme en mémoire. Il sait à présent qu'il existe un sous-programme nommé CalculerSurfaceDesMurs et il connait exactement les instructions qu'il contient, mais il ne les exécute pas.
Même principe pour les trois déclarations de sous-programme qui suivent.
Après avoir exécuté les instructions de lectures des données, l'interprèteur rencontre une instruction d'appel du sous-programme CalculerSurfaceDesMurs.
Cet appel va déclencher l'exécution de ce sous-programme. C'est à dire que l'interpréteur va à présent exécuter les instructions se trouvant à l'intérieur du corps du sous-programme CalculerSurfaceDesMurs. En l'occurence, il s'agit de l'instruction:
SurfaceDesMurs = \ 2 * (LargeurPiece * HAUTEUR_MUR + \ LongueurPiece * HAUTEUR_MUR);
Lorsque l'exécution de cette procédure est terminée, il y a un retour de sous-programme , c'est à dire que l'exécution continue à l'instruction qui suit l'appel du sous-programme venant d'être appelé. Dans notre cas, le retour se fait donc à l'instruction d'appel du sous-programme CalculerSurfaceDesFenetres.
Ce sous-programme sera donc exécuté et au retour, ce sera l'appel du sous-programme CalculerSurfaceDesFenetres, etc ... jusqu'à ce que tous les appels de sous-programme contenus dans le corps du programme principal soient exécutés. Et finalement, l'exécution du programme se terminera par l'affichage du résultat.
Le mécanisme de retour de sous-programme que nous avons décrit ici s'applique à tous les appels de procédure: après l'exécution d'une procédure, l'ordinateur revient automatiquement à l'instruction qui suit l'appel. Pour les fonctions, nous verrons que le mécanisme de retour est légèrement différent.
Il est possible de déclarer des sous-programmes n'importe où dans le code (même à l'intérieur d'un autre sous-programme !). Mais il y a par contre un principe qui doit être respecté: l'interprèteur doit nécessairement connaitre la fonction au moment où elle est appelée. Autrement dit, la déclaration doit précéder l'appel.
Par ailleurs, notez bien que dans un programme contenant des sous-programmes, la première instruction exécutée ne correspond pas forcément, comme dans notre exemple, à la première ligne de code du fichier. Rappelons qu'il s'agit de la première instruction du programme principal. Cette instruction sera appelée le point d'entrée dans la suite du cours.