Accueil

Tutoriel Python - sommaire

Programmes professionnels

Dans ce chapitre nous allons aborder deux notions très importantes en programmation :

Un programme structuré

Dès qu'un programme correspond à un algorithme un peu plus complexe que ce que nous avons vu jusqu'à présent, il faut le structurer.

Le programme principal est relativement court car on se contente de saisir des variable, d'appeler des sous-programmes.
Un même sous-programme peut être appelé plusieurs fois par le programme principal.

Les sous-programmes sont soit des procédures soit des fonctions.
Les procédures sont des sous-programmes qui ne retournent pas de valeurs au programme principal.
Les fonctions sont des sous-programmes qui retournent des valeurs au programme principal.

Mais avec Python cette distinction n'a pas d'intérêt pratique : les procédures et fonctions sont définies avec le même mot clé : def.
Dans le code d'une fonction il y aura une instruction return qu'on ne retrouvera pas dans une procédure.

Premier programme structuré

Objectif :

Le code source

# nom du programme : cercle_plus.py
#objet du programme : programme structuré sur le cercle

#procédures et fonctions 
def cercle1(r):
    c = rayon *2 * math.pi
    s = rayon**2 * math.pi
    return c, s

def cercle2(r):
    pencolor('navy')
    pensize(3)
    speed("slow")
    circle(r)
    exitonclick()
#------------------------------------------------
#programme principal
import math
from turtle import *
rayon = input("saisir le rayon au format  9999.99  : ")
rayon =eval(rayon) #conversion chaine en numérique
circonference, aire = cercle1(rayon)    # appel fonction cercle1
print ("circonférence du cercle : " , circonference)
print ("aire du cercle : " , aire)
cercle2(rayon)  #appel procédure cercle2

Nous avons d'abord la description d'une fonction ("cercle1") et d'une procédure ("cercle2")
Puis nous avons le programme principal dans lequel on appelle successivement la fonction "cercle1" et la procédure "cercle2".
Les deux valeurs retournées par la fonction sont récupérées dans le programme principal respectivement dans les variables circonference et aire.
J'affiche ensuite ces deux variables.

Description de la fonction "cercle1"

J'utilise la fonction pi du module math.
Les variables définies dans cette fonction sont : r, c, s

Description de la procédure "cercle2"

La variable utilisée dans cette procédure est r.
Cette variable est utilisée pour dessiner le cercle avec le module turtle.

Batterie de tests

Vous avez saisi le code source et vous vous êtes assuré qu'il fonctionne correctement.
Au fait, n'oubliez pas de cliquer dans la fenêtre graphique pour "reprendre la main".

Maintenant vous allez découvrir via des tests, la notion de portée des variables ainsi que la problèmétique des erreurs de saisie.

Premier test : dans la fonction et la procédure vous rajoutez l'instruction "print(rayon)"

Exécutez de nouveau le programme !
Pas de plantage : le rayon est affiché deux fois.
Supprimez logiquement les rajouts : transformer instructions en commentaires.

Deuxième test : dans le programme principale rajoutez " print(c,s)"

Puis lancez l'exécution.
Plantage !

Traceback (most recent call last): File "C:/Users/boulanger/Documents/pythons_programmes/cercle_plus.py", line 28, in <module> print (c,s) NameError: name 'c' is not defined

Tout cela est normal.

Une variable définie au niveau d'un sous-programme (procédure ou fonction) n'est connue que de cette routine ; elle ne peut être manipulée dans le programme principal.
Par contre une variable définie au niveau du programme principal peut être manipulée également dans les sous-programmes. Cette variable a donc une portée plus grande.

Nouveau test

Lancez l'exécution du programme et saisissez la chaine "100 cm" .

Traceback (most recent call last): File "C:\Users\boulanger\Documents\pythons_programmes\cercle_plus.py", line 24, in <module> rayon =eval(rayon) #conversion chaine en numérique File "<string>", line 1 100 cm ^ SyntaxError: unexpected EOF while parsing

L'utilisateur saisit une suite de chiffres ET de lettres. La fonction eval() est capable de transformer une chaine en numérique mais à condition que la saisie ne comporte que des chiffres. Donc ici, il y a "plantage". C'est la faute de l'utilisateur qui n'a pas lu l'invite de commande : "saisir le rayon au format 9999.99  ".
Mais un bon programme doit pallier aux étourderies de l'utilisateur.
Il faut donc améliorer ce programme et prévoir un contrôle de saisie.
C'est l'occasion d'introduire une notion très puissante mais parfois un peu délicate : les expressions régulières.
On retrouve ce concept dans tous les langages. Ainsi le lecteur qui maitrise JavaScript va retrouver une syntaxe déjà connue.

Nouvelle écriture du programme principal

Extrait :

#programme principal
import math
from turtle import *
import re
rayon =""
gabarit ="^[0-9]{1,}$"
while not re.search(gabarit, rayon):
    rayon = input("saisir le rayon au format  9999.99  : ")
     
rayon =eval(rayon)      #conversion chaine en numérique
...

Whou ! ça se complique sérieusement.
Voyons toutes les nouveautés :
import re : activation du module re (Regular Expressions) donc le module qui traite des expressions régulières
gabarit ="^[0-9]{1,}$" : la variable gabarit contient une expression régulière qui veut dire "au moins un chiffre".
while not re.search(gabarit, rayon) : tant que le contenu de rayon ne correspond pas au format de saisie défini dans gabarit il faut boucler donc ressaisir le rayon.
Nous avons donc utilisé la méthode search() du module re. et aussi la syntaxe while not … (tant que faux)

Construction d'une expression régulière

Une expression régulière est une chaine qui commence par le caractère "^" et se termine pas "$" puis comprend 1 à N couples "classe – quantificateur".
Une classe est délimitée par des crochets, le quantificateur est délimité par des accolades.
Dans l'exemple précédent il n'y avait qu'un couple "classe-quantificateur".

Les classes

Une classe indique le ou les caractères autorisés à la saisie. On reconnait une classe car elle est entre crochets.
Une classe peut être un énumération de caractères autorisés ou un intervalle ou un mélange des deux.

Les quantificateurs

Un quantificateur suit une classe et indique le nombre de caractères autorisés à la saisie. Un quantificateur est entre accolades ou est un symbole :

Programme de saisies multiples avec contrôle de saisie systématique

Grâce à ce programme un invidu peut créer son espace personnel sur un site.

Le code source

#nom programme : saisies_multiples.py
# objet : maitriser la controle de saisie
import re
telephone =""
mail =""
nom =""
prenom =""
motpasse =""

nom_g = "^[A-z ']{2,}$"
prenom_g = "^[A-z ']{2,}$"
telephone_g = "^[0-9]{10}$"
motpasse_g = "^[A-z0-9 ]{8,}$"

while not re.search(nom_g, nom):
    nom = input("Nom sans lettres accentuées : ")
while not re.search(prenom_g, prenom):
   prenom = input("prénom sans lettres accentuées : ")
while not re.search(telephone_g, telephone):
    telephone = input("téléphone (suite de 10chiffres collés) : ")
while not re.search(motpasse_g, motpasse):
    motpasse = input("Mot de passe (Seulement chiffres, lettres Maj ou min) : ")
while not "@" in mail:
    mail = input("adresse mail ?  (caractère @ obligatoire)  : ")
nom =nom.upper()
prenom =prenom.lower()
print ("nom : ",  nom , "prénom : " , prenom , "téléphone : ", telephone, "adresse mail : ", mail, 
"mot de passe : " , motpasse)

Exécution du programme

Nom sans lettres accentuées : Darche 
prénom sans lettres accentuées : pat66
prénom sans lettres accentuées : pat
téléphone (suite de 10chiffres collés) : a123456789
téléphone (suite de 10chiffres collés) : 0123456789
Mot de passe (Seulement chiffres, lettres Maj ou min) : sesame!62
Mot de passe (Seulement chiffres, lettres Maj ou min) : Sesame62
adresse mail ?  (caractère @ obligatoire)  : darchepat.gmail.fr
adresse mail ?  (caractère @ obligatoire)  : darchepat@gmail.fr
nom :  DARCHE  prénom :  pat téléphone :  0123456789 adresse mail :  darchepat@gmail.fr 
mot de passe :  Sesame62

L'utilisateur a droit à n essais pour saisir correctement les données.
La trace ci-dessus indique qu'il s'est repris à deux fois pour saisir le prénom, le téléphone, le mot de passe et l'adresse mail.

Analyse du code

Examinons les différents gabarits que doit respecter l'utilisateur :
nom_g = "^[A-z ']{2,}$" : pour le nom il doit saisir au moins deux lettres Maj ou Min mais aussi espace et apostrophe puisque ces deux caractères sont définis dans la classe (entre z et le crochet fermant).
prenom_g = "^[A-z ']{2,}$" : pour le prénom c'est la même chose.
telephone_g = "^[0-9]{10}$" : l'utilisateur doit saisir impérativement 10 chiffres et uniquement des chiffres.
motpasse_g = "^[A-z0-9]{8,}$" : l'utilisateur doit saisir au moins 8 chiffres ou lettres Maj ou Min. Les autres caractères sont interdits.
Pour la saisie du mail, je n'ai pas prévu de gabarit. Je vérifie seulement si la chaine comprend le caractère "@". On aurait pu imaginer une expression régulière pour définir un gabarit mais c'est un peu difficile.
Avant d'afficher toutes ces informations, on convertit le nom en une suite de lettres majuscules et le prénom en une suite de lettres minuscules.

Une routine avec une expression régulière complexe

Je vous propose une routine qui permet de saisir un numéro de téléphone au format 99 99 99 99 99 .

Le code source

#nom programme : saisie_telephone.py
import re
telephone =""
telephone_g = "^([0-9]{2}[ ]{1}){5}$"
while not re.search(telephone_g, telephone):
    telephone = input("Tapez le n° de téléphone au format '99 99 99 99 99 ' : ")

longueur = len(telephone)
print ("Numéro de téléphone : ", telephone," ", "longueur : ", longueur)

L'expression régulière

Notez les parenthèses dans l'expression régulière.
L'expression contient un groupe (entre parenthèses) qui doit être répèté 5 fois.
Dans le groupe une classe [0-9] suivi de {2} puis une autre classe [ ] suivie de {1}.
Il faut donc saisir 5 fois : 2 chiffres suivis d'un espace. ; les autres caractères sont interdits.

Attention à la saisie d'une expression régulière : pas d'espace entre ^et $ (tout collé).

Trace du programme

Tapez le n° de téléphone au format '99 99 99 99 99 ' : 01 02 03 04 05 
Numéro de téléphone :  01 02 03 04 05  longueur : 15

La longueur de la chaine contenue dans "téléphone" est 15 à cause de l'espace final.
Ça ne serait pas très difficile de le supprimer ...

Tirage au sort de cinq cartes : version définitive

Dans le chapitre 8 le programme avait déjà été amélioreé avec l'emploi d'un ensemble interdisant les doublons mais alors "la main" du joueur pouvait alors être inférieure à 5 cartes ...

Dans la version définitive le programme est structuré afin d'être flexible.
Il faut parfois plus de cinq tirages, si le tirage au sort produit des doublons.
Une fonction nommée "tirage_carte()" sera appelée au moins 5 fois (parfois plus) par le programme principal. ... Il faut appeler cette fonction jusqu'à ce que la longueur de l'ensemble "mon_jeu" soit égale à 5.

Le code

# nom programme : tirage_carte_fonction #objet : tirage au sort de 5 cartes. """ Version améliorée : les cartes tirées sont rangées dans un ensemble. Ainsi il ne peut y avoir de doublons. """ # fonction def tirage_carte(): carte_e = choice (enseignes) carte_r = choice (rang) carte_tiree = str(carte_r) + " de " + carte_e return carte_tiree #programme principal from random import * enseignes = ['pique', 'coeur', 'carreau', 'trèfle'] rang = ['As', 'Roi', 'Dame', 'Valet', 10, 9, 8 , 7] reponse ="o" while reponse in "Oo": mon_jeu =set() # la main stockée dans un ensemble n = 0 while n < 5: carte = tirage_carte() #appel fonction mon_jeu.add(carte) n = len(mon_jeu) print("Mon jeu : ") for carte in mon_jeu: print(carte, end =" - ") print("\n ----------------------------------------------") reponse =input("Encore un tirage o/n ? : " )

Tant que n (nombre d'éléments du set "mon_jeu" est inférieur à 5, il faut boucler.
La variable "carte" récupère la valeur retournée par la fonction.

Trace de l'exécution

Mon jeu : 
As de coeur - Dame de trèfle - 7 de coeur - 9 de trèfle - Valet de coeur - 
 ----------------------------------------------
Encore un tirage o/n  ? : o
Mon jeu : 
10 de pique - 8 de pique - Dame de coeur - Roi de pique - 9 de coeur - 
 ----------------------------------------------
Encore un tirage o/n  ? : o
Mon jeu : 
As de coeur - 7 de pique - 9 de carreau - 8 de carreau - Valet de coeur - 
 ----------------------------------------------
Encore un tirage o/n  ? : n

Fin de ce chapitre !

Dans le chapitre suivant nous aborderons les fichiers de données.