Accueil
Mes tutoriels sur la programmation

Tutoriel Python - sommaire


Vous pouvez me contacter via Facebook (questions, critiques constructives) : page Facebook relative à mon site

Contrôles de saisie, distribuer ses programmes, créer ses modules

Dans ce chapitre je vais tenter de vous montrer comment améliorer vos programmes et comment partager votre production.

De bonnes pratiques

Les bonnes pratiques de programmation Python sont proposées dans le cadre du PEP (Python Enchancement Proposal : propositions d'améliorations de Python)

Indentation

Vous savez qu'un bloc d'instruction appelé par un while OU un if OU un else OU elif doit être décalé par rapport à l'instruction d'appel.

Longueur maximale d'une ligne d'instruction

Une ligne ne doit pas dépasser 79 caractères.
Pour indiquer qu'une instruction n'est pas terminée il faut rajouter en fin de ligne la barre oblique inverse. On peut aussi ouvrir une parenthèse (qui est fermée dans la ligne suivante).

Directives d'importation

Syntaxe déconseillée :

import os, math, matplolib, tKinter

Cette instruction est déconseillée car peu lisible
Il est conseillé d'écrire plutôt :

import os
import math
import tKinter as tk

Utilisez des alias pour les modules ayant un nom très long ou qui doit respecter une certaine casse.
Les importations doivent se trouver en début de programme.

Attention à la casse

Python fait la différence entre majuscule et minuscule. On dit qu'il tient "compte de la casse".
Exemple :

>>> maChaine ="bonjour" >>> machaine NameError: name 'machaine' is not defined

Il y a une exception (erreur) puisque "machaine" (sans C majuscule) n'existe pas.

Les espaces

Évitez les espaces au coeur des parenthèses, crochets et accolades.
Pas d'espaces autour du signe "=".

Nommer les variables et fonctions

Le premier caractère ne peut être un chiffre, pas de lettres accentuées.
Évitez les lettres majuscules. À défaut au début de chaque mot composé. Exemple : maListe (notation en "CamelCase")

Donnez des noms logiques à vos variables. Si une variable sert de compteur appelez la "compteur" ; si elle doit contenir le score d'une partie appelez la "score".
Je rappelle qu'un mot réservé ne peut être employé pour nommer une variable ou fonction.
Pas de trait d'union dans un nom de variable mais le trait de soulignement("tiret bas").
Pour les variables dont le nom ne comprend qu'un seul caractère il ne faut pas employer : O (o majuscule), l( L minuscule) et I(i majuscule). En effet avec certaines polices le o majuscule peut être confondu avec zéro, le L minuscule avec 1 et I majuscule avec l.
L'usage veut qu'une variable contenant un indice de séquence soit stocké dans une variable "i" (i minuscule).
Les constantes doivent être écrites en majuscules avec des traits de soulignement si le mot est composé.
L'affectation doit se faire avec un tuple.
Exemple :

TAUX_REDUIT, TAUX_NORMAL = (5.5, 20) 

Les commentaires

Les commentaires peuvent être écrits sur plusieurs lignes à condition d'être encadrés par des guillemets triples (""").

Les messages

Évitez les fautes d'orthographe. Si les messages dans les fonctions input() & print() sont délimités par des guillemets doubles vous pouvez utilisez les apostrophes dans ces chaines.

Évitez les exceptions

Dans le chapitre 12 nous avons abordé la "gestion des exceptions" ; en d'autres termes, les erreurs de saisie.
Personnellement je trouve que la syntaxe correspondant à la gestion des exceptions est lourde.
Gérer les exceptions c'est bien, faire en sorte qu'elles ne puissent survenir c'est encore mieux.

Exemple : programme sur le cercle

Le programme calcule la circonférence et l'aire du cercle à partir du rayon ; le cercle est dessiné.
Le rayon étant saisi par l'utilisateur, il y a donc un risque réel d'erreur de saisie.

Le code

# nom du programme : cercle.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
    #print(rayon)
    return c, s

def cercle2(r):
    #print(rayon)
    pencolor('navy')
    pensize(3)
    speed("slow")
    circle(r)
    exitonclick()
#------------------------------------------------
#programme principal
import math
from turtle import *
rayon = input("saisir le rayon sous forme d'un entier : ")
rayon =eval(rayon)      #conversion chaine en entier

circonference, aire = cercle1(rayon)    # appel fonction cerccle1
print ("circonférence du cercle : " , circonference)
print ("aire du cercle : " , aire)
print("N'oubliez pas de fermer la fenêtre contenant le graphique")
cercle2(rayon)  #appel procédure cercle2

Notez aussi que la première fonction retourne deux valeurs. d'où l'instruction : circonference, aire = cercle1(rayon)

Exécution du programme

L'utilisateur a mal lu les consignes et il saisit "100 cm". Il y alors un plantage !
la fenêtre d'exécution de l'IDLE affiche :

saisir le rayon sous forme d'un entier : 100cm Traceback (most recent call last): File "C:\python_prog\cercles.py", line 23, in <module> rayon =eval(rayon) #conversion chaine en entier File "<string>", line 1 100cm ^ SyntaxError: unexpected EOF while parsing

La méthode eval() ne peut convertir une chaine en nombre qu'à la condition que ladite chaine ait un format numérique (des chiffres et éventuellement un point parmi les chiffres).

La solution

Plutôt que gérer l'erreur de saisie, nous allons faire en sorte qu'elle ne puisse plus se produire. Nous allons donc mettre en place un contrôle de saisie.
Dans le programme principal il suffit de remplacer l'instruction input() par trois instructions :

	rayon =""
	while not rayon.isdigit():
		rayon = input("saisir le rayon sous forme d'un entier  : ")

La méthode de chaine isdigit() retourne VRAI si ladite chaine ne comprend que des chiffres.
Donc on boucle tant que la variable "rayon" comprend autre chose que des chiffres.
N'oubliez pas de créer la variable "rayon" avant l'instruction "while not rayon isdigit()" sinon vous aurez un "plantage" avec le message: "NameError: name 'rayon' is not defined"

Remarque

Et si l'on veut saisir en guise de rayon un nombre décimal ?

Essayez, tapez en guise de rayon le nombre décimal "50.5". Vous ne quittez pas la boucle de saisie puisque la condition dans le WHILE retourne toujours True.
Il faut trouver une solution pour que l'on puisse saisir en guise de rayon un nombre décimal !

Il manque une méthode de classe permettant de vérifier si une chaine a un format décimal (un point entouré de chiffres).
Peut-être dans une version prochaine de Python ...

Une astuce

Une astuce que j'ai trouvée sur la "toile" et qui est basée sur la méthode replace().

rayon =""
while not rayon.replace("." ,"").isdigit():
	rayon = input("saisir le rayon sous forme d'un nombre entier ou décimal  : ")

Avant de tester avec la méthode isdigit() il suffit de remplacer dans "rayon" le point décimal par "".

Nous pouvons aller plus loin dans le contrôle de saisie. Il y a des utilisateurs vraiment étourdis qui peuvent saisir des espaces avant et après le nombre et sans s'en rendre compte. l faut donc tester une chaine débarassée des espaces.

rayon =""
while not rayon.replace("." ,"").strip().isdigit():
    rayon = input("saisir le rayon sous forme d'un nombre entier ou décimal  : ")

J'ai donc chainé cette fois trois méthodes.

Lorsque vous ne trouvez pas votre bonheur parmi les méthodes d'une classe, pensez à chainer plusieurs méthodes.

Solution plus classique

Avant de découvrir l'astuce ci-dessus, j'avais pensé à la construction d'une expression régulière.
Le concept d'expression régulière existe, en effet, dans tous les langages et a été évoquée dans un chapitre précédent.

Nouveau code du programme principal (extraits):

...
import re
...
gabarit = "^[0-9.]{1,}$"
rayon =""
while not re.search(gabarit,rayon): 
    rayon = input("saisir le rayon sous forme d'un nombre entier ou décimal  : ")

Ne pas oublier d'importer le module re (comme "regular expression").
Je définis un gabarit de saisie dans la variable "gabarit". Les caractères autorisés sont les chiffres et le point.
Tant que la valeur saisie dans "rayon" ne correspond pas à ce gabarit, je boucle pour recommencer la saisie.

Trace d'exécution du programme :

saisir le rayon sous forme d'un nombre entier ou décimal  : 50,5
saisir le rayon sous forme d'un nombre entier ou décimal  : 50O
saisir le rayon sous forme d'un nombre entier ou décimal  : 50.5
circonférence du cercle :  317.3008580125691
aire du cercle :  8011.84666481737
N'oubliez pas de fermer la fenêtre contenant le graphique

Exercice

À vous de bosser un peu. Ainsi vous verrez si vous avez assimilé toutes ces notions.
Vous devez créer un programme structuré qui calcule le périmètre et la surface d'un rectangle et dessine ledit rectangle.
Comme dans l'exemple prévoyez un programme principal contenant deux procédures (dont une fonction) qui retourne deux valeurs.
Dans le programme principal il y a deux saisies (longueur et largeur). Sachant que les dimensions peuvent être des nombres décimaux, prévoyez un contrôle de saisie efficace, toujours en vous inspirant de l'exemple.

Je vous communique la trace d'exécution du programme :

Saisir la longueur (pas de symboles autres que chiffres et le point décimal)  : 50,50
Saisir la longueur (pas de symboles autres que chiffres et le point décimal)  : 50.50
Saisir la largeur (pas de symboles autres que chiffres et le point décimal)  : 30,o
Saisir la largeur (pas de symboles autres que chiffres et le point décimal)  : 30.5
Le rectangle a un périmètre de  162.0  et une aire de  1540.25
N'oubliez pas de fermer la fenêtre contenant le graphique

Encore un programme amélioré

Vous vous souvenez du petit programme qui consistait par essais successifs à trouver un entier généré de façon aléatoire.

Le code du programme

# nom programme : nombre_a_trouver_plus.py def unepartie(): score = 10 nbre_secret = randint(1,100) while True: nbre_joueur ="" while not nbre_joueur.isdigit(): nbre_joueur = input("Saisir un entier inférieur à 100 : ") if nbre_secret ==int(nbre_joueur): print (f"Enfin trouvé ; ton score : {score}") if score <0: score =0 return score break elif nbre_secret > int(nbre_joueur): print(f"{nbre_joueur} trop petit",end=" * ") score -= 1 # équivaut à score = score -1 else: print(f"{nbre_joueur} trop grand", end=" * ") score -= 1 # équivaut à score = score -1 # fin fonction # programme principal from random import * points = 0 print("Instructions : l'ordinateur produit de façon aléatoire un entier compris entre 1 et 99") print("Tu dois découvrir cet entier avec le moins d'essais possibles") print("Tu joues 5 fois et ensuite ton score final s'affiche") print("-----------------------------à toi de jouer ----------------------") for i in range(5): score_partie = unepartie() # appel de la fonction unepartie points=points +score_partie print(f"{points} sur un total de 50")

La fonction retourne le score d'une partie d'où l'instruction : score_partie = unepartie()