Alexandre HURSTEL
Université de Strasbourg
Master Observation de la Terre et Géomatique
3 octobre 2016
( disponible sur http://alexandre.hurstel.eu/cours/m1_otg/diapos.html )
Vous pouvez suivre l'évolution de ce cours via son flux rss. [W]
Un ordinateur est une machine programmable traitant de l'information dont le comportement est construit par l'exécution d'innombrables programmes.
Le processeur « déroule » le programme chargé en mémoire: il lit les instructions séquentiellement et les exécute au fur et à mesure
En C++:
int main(int argc, char* argv[]){
float a, b, c;
std::cout << "Entrez 3 nombres successifs: " << std::endl;
std::cin >> a;
std::cin >> b;
std::cin >> c;
float moyenne= (a + b + c) / 3.0;
std::cout << "La moyenne est: " << moyenne << std::endl;
return 0;
}
En python :
if __name__ == "__main__":
a= float(input("Entrez 3 nombres successifs: "))
b= float(input())
c= float(input())
moyenne= (a + b + c) / 3
print("La moyenne est: " + str(moyenne))
if __name__ == "__main__":
a= float(raw_input("Entrez 3 nombres successifs: "))
b= float(raw_input())
c= float(raw_input())
moyenne= (a + b + c) / 3.0
print("La moyenne est: " + str(moyenne))
Exercice: écrire un algorithme de distributeur de tickets de transport à pièces
⚠ Cet algorithme peut être affiné en précisant certaines tâches.
3. Attendre que l'utilisateur ait introduit une somme d'argent
3. Attendre que l'utilisateur introduise une pièce de monnaie
3.1 Si la pièce n'est pas reconnue, retourner en 3.
3.2 Ajouter la valeur de la pièce à la somme déjà introduite
3.3 Si la somme introduite est inférieure au prix à payer, retourner en 3.
4. Si la somme payée est supérieure au prix, rendre la monnaie
4. Si la somme versée est (strictement) supérieure au prix demandé:
4.1 Calculer la différence entre le prix demandé et la somme versée
4.2 Rendre une pièce dont la valeur est la plus proche de la somme à rendre
4.3 Déduire de la somme à rendre, la valeur de la pièce rendue
4.4 Si la somme à rendre est (strictement) supérieure à 0, retourner en 4.2
1. Demander le nombre de ticket
2. Calculer le montant à payer
3. Attendre que l'utilisateur introduise une pièce de monnaie
3.1 Si la pièce n'est pas reconnue, retourner en 3.
3.2 Ajouter la valeur de la pièce à la somme déjà introduite
3.3 Si la somme introduite est inférieur au prix à payer, retourner en 3.
4. Si la somme versée est (strictement) supérieure au prix demandé:
4.1 Calculer la différence entre le prix demandé et la somme versée
4.2 Rendre une pièce dont la valeur est la plus proche de la somme à rendre
4.3 Déduire de la somme à rendre, la valeur de la pièce rendue
4.4 Si la somme à rendre est (strictement) supérieure à 0, retourner en 4.2
5. Délivrer le nombre demandé de tickets
6. Retourner en 1.
« Les langages de programmation se divisent en deux catégories: ceux qui sont compilés et ceux qui sont interprétés. »
Et il y'a aussi les langages semi-compilés mais bon...
Il s'agit d'un langage de programmation:
Test: lancer l'interpréteur Python en tapant dans un terminal:
>: python
>>> print('mon premier script en python')
Les instructions sont exécutées une à la fois, et de façon séquentielle.
Il y a 4 types d'instructions caractéristiques:
Dans la plupart des langages de programmation les données (c'est à dire les valeurs que l'on manipule) sont typées.
En python, pour les valeurs numériques, les types de bases sont:
Les booléens, qu'on utilise dans les opérations logiques. Ils n'ont que deux valeurs possibles:
Suite quelconque de caractères, composée des caractères (même les espaces) mis entre quote ou guillemets:
Il est possible de désigner, au sein d'une chaîne, certains caractères spéciaux:
Il s'agit d'instructions permettant d'effectuer un calcul sur des valeurs numériques, donc des entiers ou flottants.
Les calculs s'effectuent grâce à des opérateurs arithmétiques:
+, -, *, /, %, **
Une expression a un résultat.
Tester:
2+2
5*4+16
12/3
9/2
15/4-1
15/(4-1)
3*3
3**3
Il s'agit d'expressions ayant pour résultat une valeur booléenne (True ou False).
Les opérateurs de comparaison sur des entiers forment des expressions logiques:
<, >, <=, >=, ==, !=
Tester:
4 > 2
2 > 4
2 < 4
4 > 4
3 <= 4
4 >= 6
4 > 4
4 == 4
4 != 4
4 >= 4
4 <= 4
On peut aussi former des expressions logiques avec des opérateurs logiques, dont les opérandes sont des valeurs booléennes:
not, and, or
a | b | a and b |
---|---|---|
True | False | False |
True | True | True |
False | True | False |
False | False | False |
a | b | a or b |
---|---|---|
True | False | True |
True | True | True |
False | True | True |
False | False | False |
a | not a |
---|---|
True | False |
False | True |
Tester:
True and False
False and True
True and True
False and False
True or False
False or True
True or True
False or False
not True
not False
not (5>3)
not (7>13)
not (True or False)
not (True and False)
True and not False
False or (87>=64)
Il existe une opération sur les chaînes appelée “ concaténation ”. Elle permet de concaténer, c'est à dire coller, 2 chaînes de caractères ensemble grâce à l'opérateur de concaténation:
Exemple:
'salut' + ' ' + 'ça' + ' va?' → 'salut ça va?'
Tester:
'salut' + 'ça'+'va?'
'salut' + ' ' + 'ça' + ' ' + 'va?'
'salut ' + ' ça ' + 'va?'
Il s'agit un emplacement mémoire auquel on attribue un nom et dans lequel on va pouvoir stocker une valeur dans le but d'y accéder ultérieurement.
Tester:
ma_variable= 5
ma_variable
4 + ma_variable
ma_variable= 2.5
ma_variable
autre_variable= 5
resultat= autre_variable * ma_ variable
resultat
⚠ Il est de bonne pratique de donner aux variables des noms ayant un sens.
En programmation, augmenter de 1 la valeur d'une variable entière s'appelle “ incrémenter la variable ”.
Exercice: À partir d'une variable a initialisée à 5, incrémenter la variable (sans utiliser une affection de a à 6).
a= 5
Solution:
a= a+1
a
Exercice: échanger les valeurs des 2 variables suivantes:
a= 5
b= 6
Solution: (utiliser une troisième variable temporaire)
tmp= a
a= b
b= tmp
Python est doté d'un typage dynamique fort.
C'est à dire qu'on a pas besoin de préciser le type des variables et des données que l'on souhaite utiliser, l'interpréteur le détermine automatiquement.
On peut tester cela en utilisant la fonction type() de python:
type(2)
type(2.)
type(2+3)
a= 2/5
type(a)
type(False)
type(False or True)
b= (2 > 5)
type(b)
c= "chaîne de caractères"
type(c)
Néanmoins, il est parfois nécessaire de préciser ou convertir le type des données que l'on souhaite utiliser.
On parle de 'cast' sur les données ou de 'caster' une variable.
En python, il existe des fonctions de cast associées aux types de base.
Tester:
float(2)
int(3.)
bool(2)
bool(0)
int(True)
int(5/2)
int(5.6)
str(8)
b= 8
"pour mettre b dans une chaîne, j'utilise str(b) ex: "+str(b)+"!"
Bien souvent, un programme, lors de son exécution, a besoin d'interagir avec l'utilisateur (informer, demander, etc.).
Dans notre contexte du terminal, python dispose d'une fonction d'affichage qui permet d'afficher une valeur:
print()
et d'une fonction de lecture d'entrée utilisateur:
input()raw_input()
Exemple:
print("salut les amis!")
input("Entrez une valeur: ")
print("salut les amis!")
raw_input("Entrez une valeur: ")
Créer un fichier texte vide et enregistrez-le avec l’extension .py:
ex: programme1.py
Chaque ligne de ce fichier correspondra à une instruction en python.
Il y'a deux façons pour exécuter le programme:
python <chemin>/programme1.py
exec(open('<chemin>/programme1.py').read())
Dans la suite "exécuter un programme" signifie créer son programme dans un fichier texte (avec l'extension .py) qu'il faudra enregistrer puis exécuter. Il ne s'agira en aucun cas d'écrire ou de copier les instructions python du programme directement dans l'interpréteur python.
Pour des raisons malignes commerciales, Windows construit ses chemins en utilisant le séparateur '\' (appelé backslash ou antislash).
Python, lui, pour des raisons de compatibilité avec les autres systèmes (Linux & Mac), construit ses chemins en utilisant le séparateur '/' (dit 'slash').
Ainsi, par exemple, pour lancer un programme situé dans le dossier 'Mes Documents' depuis l'invite de commandes [?] Windows, un utilisateur écrirait quelque chose comme cela:
python C:\Users\nom_utilisateur\Documents\mon_programme.py
En revanche, pour lancer le même programme, depuis l'interpréteur python, l'utilisateur écrirait:
exec(open('C:/Users/nom_utilisateur/Documents/mon_programme.py').read())
Astuce: Pour trouver le chemin (Windows) d'un fichier, en passant par le navigateur de fichiers, un utilisateur peut réaliser les actions suivantes:
Clique droit sur le ficher → 'Propriétés' → Onglet 'Sécurité'
L'utilisateur peut alors y trouver le chemin (Windows) complet du fichier sous le champs 'nom de l'objet:' qu'il peut copier puis coller à l'endroit désiré.
Écrire et exécuter un programme qui affiche le message:
’programmer en python est fastoche’
Solution: programme1.py
print('programmer en python est fastoche')
Écrivez un programme qui demande un entier à l’utilisateur et affiche cet entier au carré.
Solution: programme2.py
entree= input("Entrez un entier:\n")
entree= int(entree)
print( entree*entree )
entree= raw_input("Entrez un entier:\n")
entree= int(entree)
print( entree*entree )
ou
print("Entrez un entier:")
entree= int( input() )
resultat= entree**2
print("Le resultat de " + str(entree) + " au carre est " + str(resultat) + "!")
print("Entrez un entier:")
entree= int( raw_input() )
resultat= entree**2
print("Le resultat de " + str(entree) + " au carre est " + str(resultat) + "!")
Concept qu'on retrouve dans la plupart des langages de programmation.
Ce sont des parties du code sources qui n'ont volontairement aucun effet.
#calcul de la moyenne de a, b, et c.
moy= (a+b+c)/3.0 #en 2.7 div par un flottant pour une div flottante
print("ma moyenne: "+str(moy))
On s'en sert pour :
Pour répondre aux paradigmes de la programmation impérative (▲), python fournit des structures de contrôle suivantes:
Ces 3 schémas algorithmiques essentiels permettent la définition explicite de l'enchaînement des actions/instructions et servent ainsi à moduler le comportement du programme en fonction des données/paramètres.
L'utilisation des structures de contrôles va de pair avec la compréhension et l'utilisation des expressions logiques (▲)(▲).
Le comportement découlant de l'utilisation des structures de contrôle est réalisé en fonction de la réalisation ou non de certaines conditions. Réalisation (ou non) qui se modélisent suivant le résultat de l'évaluation d'une expression logique: Vrai ou Faux, en python, True ou False.
Exemple: algorithme pour déterminer un maximum entre 2 nombres a et b:
Si a > b Alors:
resultat ← a
Sinon:
resultat ← b
Afficher resultat
Permet d'exécuter une partie du code, ou de choisir entre 2 morceaux de code (blocs d'instructions) à exécuter en fonction de certains paramètres/variables.
On formalise cette structure de contrôle de la façon suivante:
Si [condition] Alors: [bloc d'instructions] Sinon: [bloc d'instructions] Fin si
Exemples en python:
|
|
L'indentation consiste à décaler un bloc d'instructions d'un nombre fixe d'espaces en début de chaque ligne. On augmente le niveau d'indentation
Cela permet de:
En python, l'indentation est obligatoire! car il intègre ces principes comme étant des règles. Ainsi:
On peux indenter d'un niveau en utilisant un nombre fixe (au choix) d'espaces en début de ligne ou en utilisant une tabulation (touche Tab).
⚠ MAIS il faut faire un choix et rester cohérent!!!
print("bloc 1 niv 0")
if condition1:
print("bloc 2 niv 1")
print("bloc 2 niv 1")
if condition2:
print("bloc 3 niv 2")
else:
print("bloc 4 niv 2")
print("bloc 4 niv 2")
print("bloc 5 niv 1")
print("bloc 5 niv 1")
print("bloc 5 niv 1")
print("bloc 6 niv 0")
Consultez les préférences de votre éditeur de texte à ce sujet (indentation automatique, largeur des tabulation, remplacer les tabulation par des espaces, etc.)
L'indentation par tabulation à l'avantage d'économiser la taille (mémoire) de vos fichiers de programmes, mais certains problèmes de portabilité entre certains éditeurs.
La majorité des programmeurs (notamment en python) utilisent des indentations par espace. [?]
"Comparer": Écrire un programme qui demande à l'utilisateur d'entrer 2 nombres successivement, puis affiche à l'écran un message explicitant la comparaison des ces 2 nombres (supérieur, inférieur ou égal).
Solution: compare.py
a= float(raw_input("Entrez une valeur numerique:"))
b= float(raw_input("Entrez une seconde valeur numerique:"))
if a==b :
print("Les valeurs sont egales")
elif a>b:
print("La premiere valeur est plus grande")
else:
print("La seconde valeur est plus grande")
a= float(input("Entrez une valeur numerique:"))
b= float(input("Entrez une seconde valeur numerique:"))
if a==b :
print("Les valeurs sont egales")
elif a>b:
print("La premiere valeur est plus grande")
else:
print("La seconde valeur est plus grande")
"Augmenter salaire": Écrire un programme qui demande à l'utilisateur d'entrer un salaire d'un employé, et qui affiche à l'écran le salaire augmenté suivant la règle suivante: un salaire d'au moins 2000 € est augmenté de 200 €, les autres le sont de 400 €.
Solution: salaire_augmente.py
salaire= float(raw_input("Entrez salaire:"))
if salaire >= 2000 :
resultat= salaire + 200
else :
resultat= salaire + 400
print("Nouveau salaire: "+str(resultat))
salaire= float(input("Entrez salaire:"))
if salaire >= 2000 :
resultat= salaire + 200
else :
resultat= salaire + 400
print("Nouveau salaire: "+str(resultat))
"Montant d'une facture": Écrire un programme qui calcul le montant d'une facture à partir d'un montant d'achat donné. Voici les règles de calcul pour cette facture:
Solution: facture.py
montant= float(raw_input("Entrez le montant des achats: "))
montant_TTC= montant * 1.20
facture= montant_TTC
if montant_TTC <= 50 :
facture= montant_TTC + 10
print("Montant facture: "+str(facture))
montant= float(input("Entrez le montant des achats: "))
montant_TTC= montant * 1.20
facture= montant_TTC
if montant_TTC <= 50 :
facture= montant_TTC + 10
print("Montant facture: "+str(facture))
Communément appelée "boucle pour" ou "boucle for", cette structure de contrôle permet de répéter l'exécution d'un bloc d'instructions un nombre de fois déterminé.
On formalise cette structure de contrôle de la façon suivante:
Pour [variable] allant de [expression] à [expression] Répéter: [bloc d'instructions] FinPour
Exemples en python:
|
|
|
Version commune: génère une liste puis parcours les éléments un à un à chaque nouveau passage dans la boucle. |
Version rapide: génère l'élément suivant à chaque nouveau passage dans la boucle: économie en mémoire et et temps |
#afficher les nombres de 1 à 9
for i in range(1,10):
print(str(i))
Dans la version 3.6 il n'y a pas de variante ( le xrange() de la version 2.7 a remplacé le range() original qui a été supprimé ).
"Table de multiplication": Pour un entier donné par l'utilisateur, écrivez un programme qui affiche sa table de multiplication de 1 à 10.
Solution: table_mult.py
a= int(raw_input("Entrez un entier: "))
for i in xrange(1,11):
print(str(a)+'*'+str(i)+"="+str(i*a))
a= int(input("Entrez un entier: "))
for i in range(1,11):
print(str(a)+'*'+str(i)+"="+str(i*a))
"Table de multiplication dynamique": Pour 3 entiers a, b et c donnés par l'utilisateur, écrivez un programme qui affiche la table de multiplication de a de b à c.
Solution: table_mult_2.py
a= int(raw_input("Entrez un entier: "))
b= int(raw_input("Entrez un second entier: "))
c= int(raw_input("Entrez un deuxieme entier: "))
for i in xrange(b,(c+1)):
print(str(a)+'*'+str(i)+"="+str(i*a))
a= int(input("Entrez un entier: "))
b= int(input("Entrez un second entier: "))
c= int(input("Entrez un deuxieme entier: "))
for i in range(b,(c+1)):
print(str(a)+'*'+str(i)+"="+str(i*a))
"Somme des n premiers entiers naturels": Pour un entier n, donné par l'utilisateur, écrivez un programme qui calcule et affiche la somme des n premiers entiers naturels.
Solution: somme_entiers.py
n= int(raw_input("Entrez un entier: "))
somme= 0
for i in xrange((n+1)):
somme= somme + i
print("La somme des "+str(n)+" premiers entiers est: "+str(somme))
n= int(input("Entrez un entier: "))
somme= 0
for i in range((n+1)):
somme= somme + i
print("La somme des "+str(n)+" premiers entiers est: "+str(somme))
Il s'agit de « dérouler » (ou "d'exécuter") un algorithme « à la main », à la manière d'un ordinateur.
Cela se fait à partir d'un scénario d'exécution fournissant les valeurs.
En pratique, cela consiste à lire le code ligne par ligne et d'exécuter les instructions (en prenant en compte les structures de contrôles) en remplissant un tableau qui garde la trace de chaque valeur des variables du programme lors de chaque instruction selon le principe suivant :
Scénario d'exécution: l'utilisateur entre successivement les valeurs: 4, 1, 3, 9 puis 2.
m= 0 #<1
m= 0 #<1
|
|
Instructions: | m | i | a |
1 | 0 | - | - |
2 | 0 | 0 | 4 |
3 | 4 | 0 | 4 |
2 | 4 | 1 | 1 |
2 | 4 | 2 | 3 |
2 | 4 | 3 | 9 |
3 | 9 | 3 | 9 |
2 | 9 | 4 | 2 |
4 | 9 | 4 | 2 |
Exercice: À votre avis que représente la valeur de m affichée à la fin du programme?
"Factorielle": En n'utilisant que des "boucles for" et des additions, écrivez un programme qui, pour un entier n donné par l'utilisateur, calcule et affiche la factorielle de n (notée n!) [W]
Indications:
Une méthode pour simplifier la résolution de cet exercice est de procéder en 3 étapes
n= int(raw_input("Entrer n: "))
m= int(raw_input("Entrer m: "))
#multiplication n * m :
res= 0
for i in xrange(0,m):
res= res + n
print(str(n)+" * "+str(m)+" = "+str(res))
n= int(input("Entrer n: "))
m= int(input("Entrer m: "))
#multiplication n * m :
res= 0
for i in range(0,m):
res= res + n
print(str(n)+" * "+str(m)+" = "+str(res))
k= int(raw_input("Enter k: "))
#k!
res= 1
for j in xrange(1,k+1):
f= f * j
print(str(k)+"! = "+str(f))
k= int(input("Enter k: "))
#k!
f= 1
for j in range(1,k+1):
f= f * j
print(str(k)+"! = "+str(f))
Nous avons donc :
Il suffit donc simplement de remplacer chaque multiplication dans le programme implémentant la factorielle par notre implémentation de la multiplication. En pratique cela se fait facilement en identifiant simplement quelle variable, dans notre boucle multiplicative, les variables qui correspondent aux opérateurs de la multiplication. Dans ce que l'on a écrit précédement il s'agit des variables n et m.
k= int(input("Enter k: "))
#k!
f= 1
for j in range(1,k+1):
#remplace f * j:
res= 0
for i in range(0,j):
res= res + f
#ne pas oublier l'affectation du resultat (f=f*j):
f= res
print(str(k)+"! = "+str(f))
k= int(raw_input("Enter k: "))
#k!
f= 1
for j in xrange(1,k+1):
#remplace f * j:
res= 0
for i in xrange(0,j):
res= res + f
#ne pas oublier l'affectation du resultat (f=f*j):
f= res
print(str(k)+"! = "+str(f))
Communément appelée "boucle tant que" ou "boucle while", cette structure de contrôle permet de répéter des blocs d'instructions tant qu'un condition est remplie (tant qu'une expression logique n'est pas évaluée à True).
On formalise cette structure de contrôle de la façon suivante:
Tant que [condition] Répéter: [bloc d'instructions] FinTantQue
⚠ Peut engendrer des boucles infinies si la condition est mal définie!
Exemple en python:
#tant que l'utilisateur n'entre pas "stop", le programme continue de demander une entrée
a=""
while a!="stop" :
a= str(input("Entrez du texte: "))
#tant que l'utilisateur n'entre pas "stop", le programme continue de demander une entrée
a=""
while a!="stop" :
a= str(raw_input("Entrez du texte: "))
"Re-table de multiplication dynamique": reprendre l'énoncé de la deuxième partie de l'exercice 4 (▲), mais en utilisant une boucle while.
Solution: table_mult_while.py
a= int(input("Entrez un entier: "))
b= int(input("Entrez un second entier: "))
c= int(input("Entrez un deuxieme entier: "))
i= b
while i<=c:
print(str(a)+'*'+str(i)+"="+str(i*a))
i= i+1
a= int(raw_input("Entrez un entier: "))
b= int(raw_input("Entrez un second entier: "))
c= int(raw_input("Entrez un deuxieme entier: "))
i= b
while i<=c:
print(str(a)+'*'+str(i)+"="+str(i*a))
i= i+1
"Épeler un nombre": Pour un entier donné par l'utilisateur, écrivez un programme qui affiche ce nombre chiffre par chiffre en toute lettre.
Exemple: 1546 affiche "Un Cinq Quatre Six"
Indications:
Solution: epeler_nb.py
a= int(input("Entrez un entier: "))
res= ""
while a>0:
r= a%10
if r==0 :
res= "Zero " + res
elif r==1 :
res= "Un " + res
elif r==2 :
res= "Deux " + res
elif r==3 :
res= "Trois " + res
elif r==4 :
res= "Quatre " + res
elif r==5 :
res= "Cinq " + res
elif r==6 :
res= "Six " + res
elif r==7 :
res= "Sept " + res
elif r==8 :
res= "Huit " + res
else :
res= "Neuf " + res
a= int(a/10)
print(res)
a= int(raw_input("Entrez un entier: "))
res= ""
while a>0:
r= a%10
if r==0 :
res= "Zero " + res
elif r==1 :
res= "Un " + res
elif r==2 :
res= "Deux " + res
elif r==3 :
res= "Trois " + res
elif r==4 :
res= "Quatre " + res
elif r==5 :
res= "Cinq " + res
elif r==6 :
res= "Six " + res
elif r==7 :
res= "Sept " + res
elif r==8 :
res= "Huit " + res
else :
res= "Neuf " + res
a= a/10
print(res)
⚠ Rendent le code moins lisible à utiliser avec modération
L'instruction break :
Elle permet de sortir immédiatement d'une boucle et ainsi de contrôler les cas particuliers plus facilement.
Exemple en python:
#affiche les entiers de 1 à 3
i=0
while i<=100:
i= i+1
print(str(i))
if i==3 :
break
L'instruction continue :
Elle permet de sauter un tour de boucle et ainsi de contrôler les cas particuliers plus facilement.
Exemple en python:
#affiche les entiers de 1 à 5, sauf 3
i=0
while i<5:
i= i+1
if i==3 :
continue
print(str(i))
"Mot de passe": Écrivez un programme qui demande à l'utilisateur d'entrer une chaîne de caractère. Si cette chaîne est la bonne, "alhakazam", le programme affiche "Ok", mais, si au bout de 5 essais, l'utilisateur n'a pas trouvé, le programme affiche "Denied". Utilisez une boucle pour implémenter les essais (ne pas écrire 5 essais séquentiellement...)
Solution: mot_de_passe.py
i= 1
while i<=5 :
mdp= input("Enter mot de passe (essai "+ str(i)+"): ")
if mdp=="alhakazam":
break
print("Mauvais mot de passe, reesayer.")
i= i+1
if i<6 :
print("Ok")
else:
print("Denied")
i= 1
while i<=5 :
mdp= raw_input("Enter mot de passe (essai "+ str(i)+"): ")
if mdp=="alhakazam":
break
print("Mauvais mot de passe, reesayer.")
i= i+1
if i<6 :
print("Ok")
else:
print("Denied")
Solution (sans break) : mot_de_passe2.py
i= 1
mdp=""
while (i<=5)and (mdp!="alhakazam") :
mdp= input("Enter mot de passe (essai "+ str(i)+"): ")
if mdp!="alhakazam":
print("Mauvais mot de passe, reesayer.")
i= i+1
if mdp=="alhakazam":
print("Ok")
else:
print("Denied")
i= 1
mdp=""
while (i<=5)and (mdp!="alhakazam") :
mdp= raw_input("Enter mot de passe (essai "+ str(i)+"): ")
if mdp!="alhakazam":
print("Mauvais mot de passe, reesayer.")
i= i+1
if mdp=="alhakazam":
print("Ok")
else:
print("Denied")
Plus les programmes gagnent en complexité, plus ils sont longs et moins ils sont compréhensibles ou lisibles.
D'autant plus que les programmeurs se retrouvent souvent dans la situation où ils doivent répéter certaines instructions à différents endroit du code.
La solution à ces problèmes résides dans le concept de modularité. Il s'agit de:
Pour implémenter cette modularité, dans les langages informatiques "modernes", on utilise des fonctions
Il s'agit d'un sous-ensemble d'instructions, parmi les instructions qui constituent notre programme, auquel on associe un nom pour pouvoir les exécuter plus tard quand on le souhaitera et autant de fois que l'on veut.
Exemple:
def saluer():
print("Salut!")
saluer()
print("Ca va?")
print("Je vais bien")
print("Je dois y aller")
saluer()
Le comportement de nos fonctions n'est pas nécessairement fixes, il est possible de le moduler grâces aux paramètres.
Il est possible d'écrire des fonctions auxquelles il faut passer des paramètres, lors de leur appel, et dont le comportement sera donc modifié en fonction de ces paramètres.
Les paramètres de ces fonctions permettent donc de rendre nos programmes plus modulable, adaptables et génériques.
Exemple:
def saluer(ami, heure):
if(heure<17):
print('bonjour '+ami)
else:
print('bonsoir '+ami)
saluer("Jean", 10)
print("8 heures plus tard...")
saluer("Marc", 18)
⚠ Attention au typage dynamique de python qui rend facile à oublier le type de données de nos arguments...
En python, il est possible d'attribuer des valeurs par défaut à certain paramètre. Cela permet de:
Exemple:
def saluer(ami="mon ami", heure=12):
if(heure<17):
print('bonjour '+ami)
else:
print('bonsoir '+ami)
saluer()
saluer("Marc")
saluer(heure=18)
saluer(18) #instruction invalide
Dans ce qu'on a vu jusqu'à présent, les fonctions, en python, dans leur sens de programmation impérative, se distinguaient par rapport à leurs homologues mathématiques du fait qu'elles ne prennent pas obligatoirement de paramètres, et surtout du fait qu'elles ne renvoient pas de résultat. Cependant, il est tout à fait possible de leur rajouter ce comportement, grâce à l'instruction return.
Exemple:
|
|
⚠ Attention, l'instruction return arrête l'exécution de la fonction pour renvoyer un résultat. Les instruction qui la suivent ne seront pas exécutées (si return est rencontré lors de l'exécution de la fonction).
La modularité gagnée dans les programmes grâce aux fonctions apporte également un autre avantage: la possibilité de tester nos portions de code contenus dans nos fonctions.
Une pratique saine est de vérifier ses fonctions via un jeu de test dans lequel on teste le comportement des fonctions concernées par rapport à certains paramètres qui relèvent soit de cas génériques, cas limites, ou cas particuliers en les comparant à un résultat attendu.
Si un ou plusieurs résultats de notre jeu de test ne correspond pas à nos résultats attendus, il y'a plusieurs causes possibles:
Dans tous les cas, un jeu de tests permet une détection précoce des potentielles erreurs. Même si l'écriture d'un jeu de test peut sembler faire perdre du temps, elle fait en fait gagner un précieux temps de débogage et contribue à la fiabilité du programme.
⚠ À ne pas rechigner ou sous-estimer!
"Vérification par approximation": Écrire une fonction approx qui prends en paramètre 2 valeurs numériques a et b et un paramètre optionnel delta (fixé par défaut à 0.001), et qui retourne True si a est égale à b, à delta près, False sinon.
Votre fonction doit vérifier le jeu de test suivant:
approx(2,2) #Renvoie True
approx(2, 3) #Renvoie False
approx(3, 3.001) #Renvoie True
approx(6, 6.0015) #Renvoie False
approx(7, 6.9995) #Renvoie True
approx(2, 1.9985) #Renvoie False
approx(4.6, 4.6005) #Renvoie True
approx(4.6, 4.6005, 0.0001) #Renvoie False
approx(42, 41.8, 0.1) #Renvoie False
Solution:
def approx(a, b, delta=0.001) :
res= (a-b)
if res<=0 :
res= -res
return (res < delta)
Un ordinateur compte en binaire (contrairement aux humains qui comptent (généralement [?]) en décimale). Ainsi il travail et se représente les nombre en base 2:
Décimal (Base 10): | 1 =20 | 2 =21 | 16 =24 | 21 =16+4+1 = 24+22+20 |
Binaire (Base 2): | 1 | 10 | 10000 | 10101 =10000+100+1 |
Bien entendu, en principe*, pour un ordinateur, cette représentation binaire est aussi valable pour les nombre réels (flottants):
Décimal (Base 10): | 0.5 =2-1 | 0.25 =2-2 | 0.0625 =2-4 | 0.28125 =0.25+0.03125 = 2-2+2-5 |
Binaire (Base 2): | 0.1 | 0.01 | 0.0001 | 0.01001 =0,01+0,00001 |
* En pratique cette représentation est légèrement différente [W][?], mais le principe ne change pas.
Néanmoins, cette représentation à une conséquence: certains nombre réels en base 10 sont plus difficiles (voir impossibles) à exprimer en base 2.
Exemple:
Un ordinateur est donc incapable d'avoir à sa disposition la valeur de tels nombres (comme 0.3), il ne peut en avoir qu'une valeur approximée, dont la précisions dépend du nombre de bits[W] alloué à cette précision; les flottants disposent généralement de 23 bits pour stocker cette précision.
Ainsi cette erreur de précision se propage au fil des calculs sur les flottant et finie par se retrouver dans des résultats autrement simple à représenter:
Exemple:
L'approximation de la représentation binaire des réels, et la propagation subséquente de l'erreur de précision lors des calculs successifs, rendent ce programme invalide, bien que conceptuellement et algorithmiquement correct:
i= 4.0
while (i!=4.5):
print("i="+str(i))
i=i+0.1
Ce programme boucle à l'infini!
En réalité, cela arrive parce que le programme se déroule comme suit:
i décimal théorique | i binaire (sur 8 bits de précision pour l'exemple) |
4.0 | 100,00000000 |
4.1 | +0,00011001…= 100,00011001… |
4.2 | +0,00011001…= 100,00110010… |
4.3 | +0,00011001…= 100,01001011… |
4.4 | +0,00011001…= 100,01100100… |
4.5 | +0,00011001…= 100,01111101… |
La boucle en question ne termine jamais car l'ordinateur n'évalue donc jamais i!=4.5 comme False, car il voit en réalité: 100,1!=100,01111101….
Conclusion: Il faut être vigilant sur les tests d'égalité sur les flottants/réels. Pour vérifier l'égalité entre 2 nombre flottants, issus de calculs indépendants, il vaut mieux vérifier l'approximation à un delta près. (i.e: dire «Ces 2 nombres sont égaux à 0.0001 près (par exemple).»)
"Aires et cercles": Écrire une fonction aire calculant l'aire d'un cercle d'un rayon donné et répondant aux spécifications suivantes:
Vous pouvez utiliser le jeu de tests suivant pour vérifier votre fonction:
PI= 3.14159265
aire(1) == PI #Renvoie True
aire(1) == aire(1, 2*PI, 'R') #Renvoie True
approx( aire(4, 180), aire(4, PI, 'R') )#Renvoie True
approx( aire(5, 90), 0.25 * aire(5) ) #Renvoie True
approx( aire(3, (PI/3), 'R'), (1/6.0) * aire(3) ) #Renvoie True
aire(4.2) #Renvoie ~ 55.417
aire(2.3,(PI/3), 'R') #Renvoie ~ 2.76983751975
Solution:
def aire(r, a=360, mode='C') :
PI= 3.14159265
if mode=='R' :
div= 2*PI
else :
div= 360.0
return ( ( PI * r*r ) * (a/div) )
Comme on l'a déjà vu (▲), un problème, et donc l'algorithme qui le résout peut-être découpé en sous-problèmes à résoudre
L'analyse descendante désigne la méthodologie qui consiste a effectuer ce découpage en sous-problèmes: c'est une stratégie qui consiste à décomposer un problème, en partant du général au spécifique, jusqu'à arrivé à un ensemble de sous-problèmes simples à résoudre.
La modularité via le découpage de nos programmes en fonctions facilité l'exploitation de cette méthode.
Problème: Écrire un programme qui calcule une approximation de l'aire d'un cercle de rayon r sans utiliser la formule A = π × r².
Analyse: Un cercle peut-être défini comme un polygone régulier [W] avec une infinité de côtés.
On peut donc approximer l'aire d'un cercle en calculant l'aire d'un polygone avec un nombre suffisamment élevé de côtés.
Sous-problème: Calculer l'aire d'un polygone régulier à n côtés.
Analyse: L'aire d'un polygone régulier à n côtés est la somme des triangles ABC où C est le centre de gravité du polygone et avec A et B deux extrémités d'un de ses côtés.
On peut donc calculer l'aire d'un polygone régulier à n côtés en multipliant n fois l'aire d'un des n triangles qui le compose.
Sous-problème: Calculer l'aire d'un triangle de base du polygone régulier.
Analyse: l'aire d'un triangle de base AB et de hauteur h: $\frac{\overline{AB} \times h}{2}$
On peut donc calculer séparément l'aire des triangles qui compose le polygones régulier en appliquant la formule.
Sous-problème: Calculer la longueur de la base d'un des triangles du polygone régulier.
Analyse: On sait que:
On peut donc calculer la moitié de la base d'un des triangles qui composent le polygone régulier, et donc l'aire du dit triangle.
Exercice: À partir de l'analyse descendante effectuée précédemment, écrire un programme qui regroupe les fonctions correspondant aux sous-problèmes identifiés. Ce programme utilisera ces fonctions pour calculer une approximation de l'aire d'un cercle à partir d'un entier donné par l'utilisateur.
Indications: Pour utiliser la fonction tangente, vous pouvez utiliser la fonction incluse dans le module math de python:
#importer le module math en début de fichier:
import math
#exemple d'utilisation de la fonction tangente:
math.tan( 1.57079 )
Dans le développement informatique, les programmes de tailles conséquentes sont souvent modulaires. C'est à dire que le code nécessaire à l'exécution de ces programmes n'est pas contenu dans un fichier unique, mais réparti à travers plusieurs fichiers.
Disposer d'un code modulaire ammène certains avantages:
La programmation modulaire est un principe de base de la programmation, quelque soit le paradigme de programmation que l'on adopte.
Naturellement, python intègre la programmation modulaire et cela grâce au mot à la fonction « import », qui s'utilise comme suit:
salut.py
|
main.py
|
Ici: « main.py » est l'exécutable principal, c'est à dire le fichier utilisé pour lancer le programme; « salut.py » est le module.
Pour que cet exemple fonctionne, « salut.py » et « main.py » doivent se trouver dans le même dossier/répertoire.
Dans l'exemple précédent “ import salut.py ” avait 2 fonctions:
C'est cette dernière fonctionnalité qui explique pourquoi il fallait appeler la fonction « saluer() » en écrivant “ salut.saluer() ”
Pour ne pas encapsuler le code du module dans un espace de nom, il aurait fallu écrire:
from salut import *
La fonction « import » cherche le module dans le même répertoire que le fichier qui l'appelle. Mais il est possible d'appeler un module situé dans un sous-répertoire. Par exemple, prenons le cas de figure suivant:
repertoire1 |
main.py |
repertoire2 |
__init__.py |
module.py |
Pour importer le code contenu dans « module.py », depuis « main.py », il faut écrire:
import repertoire2.module
Ici la présence du fichier (peut être laissé vide) « __init__.py » est obligatoire, dans le sous-répertoire « repertoire2 », pour signifier à python que ce répertoire peut contenir des modules.
Certains projets de dévoloppement informatique n'ont pas pour but de produire des programmes directement exécutables. Ces projets ont pour but de coder des outils qui pourront être utilisés par d'autres développeurs, leur offrant ainsi un accès rapide à des fonctions ou possibilités qui ne sont pas offertes de base par le langage de programmation utilisé.
Ces collections de nouvelles fonctionnalités, ou bibliothèques de fonctions sont appelées des librairies.
Les librairies de code permettent de ne pas “ réinventer la roue ” à chaque nouveau projet informatique. Elles sont une part incontournable du développement informatique moderne.
Python est fourni avec un certains nombre de modules, lors de son installation sur un système, qui font parties de la librairies dite « standard » [?]. Cette librairie standard contribue à faire de python un outil de script et de programation polyvalent et populaire. On y trouve aussi bien des modules apportant des fonctionnalités pour les mathématiques ( module math ), la manipuation avancé de chaînes de caractères ( string ), manipulation de certains types de fichier comme les fichiers .csv ( module csv ), manipulation de fichier d'archives ( modules gzip, zlib, bz2 ), etc.
En règle générale l'import de modules en python ( via la fonction « import » ) ne doit pas provoquer d'exécution de code.
Problème: l'utilisation de « import » provoque une lecture et une interprétation du code contenu dans le module à importer.
C'est pourquoi, en général, les modules ne continnent que des déclaration de fonctions et de variables (c'est à dire, par de calculs effectués en dehors du corps des fonctions).
Néanmoins, python ne fournit pas de moyen pour distinguer clairement les modules des programmes à exécuter (tous des fichiers .py). Et, dans certains cas, on peut vouloir qu'un fichier contenant du code soit les deux (pour avoir par exemple un programme utilisable, mais dont on veut par la suite réutiliser certaines des fonctions qui y sont écrites).
Pour pallier à ce problème, on sépare le code en deux parties:
if __name__=="__main__":
Pour mieux comprendre l'effet de la ligne de code « if __name__=="__main__": », vous pouvez tester cet exemple:
module1.py
|
module2.py
|
import module1
import module2
if __name__=="__main__":
print("Ceci est un programme pas un module")
print("Perimetre d'un cercle de rayon 3: "+str(module1.perimetreCercle(3)))
print("Perimetre d'un carre de cote 3: "+str(module2.perimetreCarre(3)))
Testez, séparément, l'exécution de module1.py, module2.py puis main.py.
Il s'agit d'un regroupement de valeurs (pas forcément de même type). Chaque valeur constitue un champs du tuple; il y'a 2 ou plus champs dans un tuples:
couple=("interstella",5555) #couple: un 2-tuple
quadruplet= (666.66, True, "Rock", "Evil") #quadruplet: un 4-tuple
#structure 'individu': regroupe age, sexe et nom
individu= (50, 'M', 'Negan') #triplet: un 3-tuple
Pour lire individuellement les champs des tuples, on utilise l'opérateur [ ]:
#acces au premier champs
age= individu[0]
#acces au deuxieme champs
sexe= individu[1]
#acces au troisieme champs
nom= individu[2]
#/!\ genere une erreur
fail= individu[3]
Cependant, les tuples sont limités, car leur champs sont constants. Autrement dit, il n'est plus possible de les modifier une fois le tuple créé.
tuple= ("la vie","l'univers","tout le reste", 42)
#/!\ genere une erreur
tuple[3]= 7
Les tuples peuvent être initialisés à partir de variables ou d'expressions, et peuvent être affichés:
a= "bonjour"
tuple= ( 5+8, a, (5>4) )
print("mon tuple: "+str(tuple))
On peut initialiser ou affecter des variables singulières à partir d'un tupes (à condition qu'il y ait autant de variables que de champs dans le tuple) :
t1, t2, t3 = (1, 2, 3) #t1= 1, t2= 2 et t3= 3
Les opérations entre 2 tuples ne résultent pas en tuples dont le contenu est le résultat de cette opération entre chaque champs des tuples opérandes. En d'autres mots :
#l'addition de 2 tuples, n'additionne pas les champs entre eux
#mais concatene simplement les 2 tuples
(4,5,6) + (7,1,2) #renvoie (4,5,6,7,1,2)
#pour additionner les champs de 2 tuples:
a= (4,5,6)
b= (7,1,2)
#renvoie (11,6,8):
(a[0]+b[0], a[1]+b[1], a[2]+b[2])
t= (4,5,6,4,3)
#donner l'indice/position d'une valeur dans un tuple:
t.index(6) #renvoie 2 (car 6 est à la 3eme position dans le tuple t)
t.index(4) #renvoie 0 (car 4 est (d'abord) à la 1ere position dans le tuple t)
#donner le nombre d ’occurrences de la valeur 2:
t.count(7) #renvoie 0
t.count(5) #renvoie 1
t.count(2) #renvoie 2
#combien y a-t-il de valeurs/champs dans un tuple?
len(t) #renvoie 5
len( (2,"ok", true) ) #renvoie 3
#une valeur est-elle dans un tuple?
(5 in t) #renvoie true
(7 in t) #renvoie false
Dans l'interpréteur python, une documentation, en anglais, sur les tuples, peut-être affichée en tapant:
help(tuple)
Les listes permettent de stocker plusieurs données à la suite. On part d'une liste vide, et on ajoute des nouveaux éléments à la liste, par la fin.
#list l vide:
l= []
#Ajout d'un premier element
l.append(5) #[5]
print(str(l))
#ajout d'un 2eme puis 3eme element
l.append(3) #[5, 3]
l.append(7) #[5, 3, 7]
print(str(l))
Il est aussi possible de déclarer une liste à partir de plusieurs éléments (sans commencer par une liste vide):
#nouvelle liste, contient deja des elements
l2= [4,3,8,0,42,9]
Les listes sont une structure de données souple qui permet une bonne flexiblité sur la gestion de leur contenu.
Plusieurs opérations de base sur les listes sont possibles : accèder à un élément, modifier un élément, connaître la taille d'une liste (combien d'éléments à l'intérieur), etc.
#2eme element de la liste
#(la liste est indexee a partir de 0)
deuxieme_elem= l2[1]
#modifier le premier elem
l2[0]= 1
print( str(l2) ) #affiche [1,3,8,0,42,9]
#taille de la liste = nb d'elements
taille= len( l2 ) #taille= 6
Les listes offrent notament la possibilté de pouvoir lire puis supprimer n'importe quel élément dans la liste.
#suppr. le dernier elem d'une liste
end= l2.pop() #equivalent, ici, à l2.pop(5)
print("elem supprime: "+str(end))
print(l2) #affiche [1,3,8,0,42]
#suppr. le premier element d'une liste
first= l2.pop(0)
print("elem supprime: "+str(first))
print(l2) #affiche [3,8,0,42]
#suppr. du 3eme elem d'une liste
ter= l2.pop(2)
print("elem supprime: "+str(ter))
print(l2) #affiche [3,8,42]
Naturellement, quand on supprime un élément d'une liste, les autres éléments sont ré-indexés. Dans l'exemple ci dessus, lorsque l'on a supprimé le premier élément, l'ancien deuxième élément de la liste est devenu le premier, l'ancien troisème est devenu le deuxième, l'ancien quatrième troisième, etc.
De la même manière qu'avec les chaînes de caractères, il est possible de concaténer 2 listes, grâce à l'opérateur de concaténation associé, désigné par le symbol '+' :
l1= [4,8,9,23]
l2= [8,6,3]
#génère une nouvelle liste: [4,3,9,23,8,6,3]
L= l1+l2
Autres opérations utiles:
#connaitre la position d'une valeur dans une liste
L.index(9) #renvoie 2
#enlever une valeur specifique d'une liste
L.remove(3) #envleve le 1er 3 dans la liste -> L=[4,9,23,8,6,3]
#ajouter une valeur dans une liste:
L.insert(3,6) #ajoute la valeur 6 a la position 3
# -> L=[4,9,23,6,8,6,3]
#compter le nombres d'une occurence d'une valeur
L.count(6) #renvoie 2
Dans l'interpréteur python, une documentation, en anglais, sur les listes, peut-être affichée en tapant:
help(list)
Exemple : d'un programme qui créé la liste contenant les n premiers entiers au carré :
l= []
n= input("Donnez un entier")
i= 0
while i < n:
l.append(i*i)
i= i+1
Exemple : d'un programme qui parcours tous les éléments d'une liste :
for i in xrange(0,len(l)):
print("L'element a l'index "+str(i)+" est: "+str(l[i]))
Variante : du programme qui parcours tous les éléments d'une liste :
#cette variante n'est adaptee que pour des fins consultatives
#n'est pas adaptee pour agir sur le contenu d'une liste
i= 0
for element in l:
print("L'element a l'index "+str(i)+" est: "+str(element))
i= i+1
Il s'agit d'une structure de données se rapprochant de la fromalisation mathématiques des ensembles [W]. Il s'agit d'une altération du concept des listes: les éléments y sont ordonnés (il vaut donc mieux utilisé uniquement des valeurs de même types en travaillant avec les ensembles) et uniques.
#declaration d'un ensemble
#-- les ensemble se crees a partir de listes
ens= set( [1,3,2,3,3] ) #cree l'ensemble 'set( [1,2,3])'
Python offre l'implémentation des opération classiques sur les ensembles.
ens1= set([1,2,3])
ens2= set([3,4,5])
ens1.add(4) #ajoute la valeur 4 a ens1 (si absente)
ens1.union(ens2) #donne set([1,2,3,4,5])
ens2.intersection(ens1) #donne set([3,4])
ens1.difference(ens2) #donne set([1,2])
#une valeur est-elle dans un ensemble?
(4 in ens1) #renvoie True
(7 in ens2) #renvoie False
#taille/nombres d'elements d'un ensemble
len(ens2) #renvoie 3
Dans l'interpréteur python, une documentation, en anglais, sur les ensembles, peut-être affichée en tapant:
help(set)
Les dictionnaires permettent de créer une collection basée sur le principe d'associations clé-valeurs. En d'autres mot on associe une donnée nomminative (généralement une chaîne de caractères) à une donnée caractéristique. Exemple :
# creer un dictionnaire qui associe un nom avec
# un age par exemple
dico= { 'toto':18 , 'pierre':21}
dico['toto'] # donne 18
# dans cet exemple la cle etait 'toto', et 18 la valeur associee
dico['pierre'] # donne 21
dico['charles'] # erreur ! cle inexistante
# cree une entree avec cle 'charles' et valeur 15
dico['charles']= 15
Quelques outils utiles:
for cle in dico : # permet d'iterer sur les cles
print cle # affichera 'toto' puis 'pierre'
for v in dico.itervalues(): # permet d'iterer sur les valeurs
print v # affichera 18 puis 21
# verifier si le dictionnaire content une cle particuliere
dico.has_key('toto') # donne True
dico.has_key('Leo') # donne False
Dans l'interpréteur python, une documentation, en anglais, sur les ensembles, peut-être affichée en tapant:
help(dict)
python version: /
[ - ]