Python
Python
Quelques définitions
PROGRAMMATION EN PYTHON 1. D’abord, on essaye de résoudre le problème (en s’autorisant des fautes d’orthographe, des
approximations, des abréviations, en s’aidant de schémas), comme quand on rédige le plan de
la dissertation avant de rédiger le texte final. C’est ce qu’on appelle un algorithme, etc’est
indépendant du langage de programmation choisi.
1.1.3 En Python
Python est un langage interprété. On disposera de deux modes d’exécution d’un code Python :
1 2
1.2. Variables, expressions, instructions 1.2. Variables, expressions, instructions
• soit on utilise l’interpréteur Python, instruction par instruction, 1.2.3 Affectation, initialisation
Affectation. Pour mémoriser une valeur dans une variable, on fait une affectation, en utilisantle
signe = (qui est ici très différent de celui utilisé en maths). Dans une affectation le membre de gauche
(identificateur) reçoit la valeur qui est à droite (qui doit d’abord être évaluée). C’est-à-direque cette
valeur (une fois calculée si nécessaire) est stockée dans cette variable.
n = 33
a = 42 + 2 * 5
1.2 Variables, expressions, instructions ch = "bonjour"
euro = 6.55957
1.2.1 Variables
Une variable est un conteneur d’information qui est identifié par son nom, c’est un endroit Initialisation. La première affectation d’une variable donnée s’appelle l’initialisation de la
pour ranger une valeur. variable. Comme son nom l’indique, la valeur d’une variable peut varier ensuite au cours de
l’exécution d’un programme. La valeur antérieure est perdue, remplacée par la nouvelle valeur.
3 4
1.2. Variables, expressions, instructions 1.2. Variables, expressions, instructions
Ce n’est pas le cas en Python. En Python, le typage est dynamique, c’est-à-dire que l’inter- >>> 20 // 3 # division entière
préteur déterminera automatiquement le type en fonction de la valeur qui a été affectée à une 6
variable (et il change quand la valeur de la variable change). On peut connaître ce type en écrivant : >>> 20 % 3 # reste de la division entière (modulo)
type(ma_var). Les types de base sont : entier (int), réel (float), chaîne de caractères (str) et 2
booléen (bool). >>> 2 > 8 # comparaison de 2 entiers, expression booléenne
False
>>> ’a’ < ’z’ # comparaison de 2 caractères, expression booléenne
>>> a = 17 <class ’str’> >>> a = (21==7*3) True
>>> type(a) >>> a >>> ’b’ < ’a’ # la comparaison respecte l’ordre alphabétique
<class ’int’> >>> a = 3.14 True False
>>> type(a) >>> type(a) >>> (2 <= 8) and (8 < 15) # conjonction pour comparer 3 entiers
>>> a = "salut" <class ’float’> <class ’bool’> True
>>> type(a) >>> (x % 2 == 0) or (x >= 0)
# disjonction, expr. bool. dont la valeur dépend de la
1.2.5 Expressions et opérateurs # valeur de la variable x (vrai si x pair ou positif)
>>> "a"+"b" # concaténation de chaînes de caractères
Dans les exemples, nous avons montré qu’il était possible de faire des opérations, par exemple en >>> "to"*3 # répétition de chaîne de caractères
écrivant 42 + 2 * 5. Cela s’appelle une expression, c’est une “formule” qui peut être évaluée "tototo"
(calculée). Une variable ou une constante est aussi une expression, mais dont on n’a pas besoin de
calculer la valeur (elle est déjà connue). Abréviations Quelques opérateurs permettent d’abréger les notations des affectations d’une
3*2.0 - 5 valeur dans une variable qui dépend de son ancienne valeur. Par exemple :
multiplication *, puissance **, division réelle /, modulo %, division entière // Priorité des opérateurs Lorsqu’une expression comporte plusieurs opérateurs, afin de savoir
dans quel ordre elle est évaluée, on considère la priorité des opérateurs. Par exemple en arithmé-
• de comparaison (sur nombres ou chaînes de caractères, produisent un résultat de type tique vous avez appris que la multiplication est plus prioritaire que l’addition, ainsi 2 ∗ 3 + 4 est
booléen) : ==, !=, <, , >, <=, >= évalué en (2 ∗ 3) + 4 = 6 + 4 = 10 et non pas en 2 ∗(3 + 4) = 2 ∗ 7 = 14.
• logiques (entre des booléens, résultat booléen) : or (disjonction), and (conjonction), not Opérateurs par ordre de priorité décroissante : • < : Inférieur
(négation). > : Supérieur
• ** : Puissance
<= : Inférieur ou égal
Exemples d’opérateurs : • * : Multiplication >= : Supérieur ou égal
/ : Division == : Égal
>>> 2 + 3 # addition // : Division entière != : Différent
5
>>> 2 * 3 # multiplication • % : Modulo
6 • in : Appartenance
• + : Addition
>>> 2 ** 3 # puissance • not : Négation booléenne
- : Soustraction
8
>>> 20 / 3 # division réelle • and : Conjonction booléenne (et)
6.666666666666667 • or : Disjonction booléenne (ou)
5 6
1.3. Outils utiles 1.4. Entrées / Sorties
l’écran (si demandé), et attend que l’utilisateur entre une donnée au clavier et la valide par un appui
Évaluation des expressions Quand des opérateurs sont de même priorité, l’expression est
sur la touche Entrée.
évaluée de gauche à droite. En cas de doute et pour améliorer la lisibilité, il est conseillé de
parenthéser les expressions pour s’assurer qu’elles soient évaluées dans l’ordre souhaité.
1.2.6 Instructions
Une instruction est une action à exécuter par le programme. Un programme informatique est
constitué d’une suite d’instructions exécutées dans l’ordre pour atteindre un résultat. Par exemple,
une affectation de valeur dans une variable est une instruction. Dans la suite de ce cours nous allons
apprendre :
• des types de données plus ou moins complexes (booléens, listes, dictionnaires, fichiers)
• des structures de contrôle qui permettent d’écrire des programmes plus complexes quede
simples séquences d’instructions : exécution sélective / conditionnelle (if), répétition en
boucle (for, while).
• Pour lui fournir les données à traiter, en général au clavier -> entrées
• Pour pouvoir connaître le résultat d’exécution d’un programme, ou pour que le programme
puisse écrire ce qu’il attend de l’utilisateur, en général texte écrit à l’écran -> sorties
Pour gérer les entrées au clavier, on utilise la fonction input(). Quand l’ordinateur exécutela
fonction input(), il interrompt l’exécution du programme, affiche éventuellement un message à
7 8
1.4. Entrées / Sorties 1.4. Entrées / Sorties
Saisie textuelle et conversion de type. La fonction input() effectue une saisie en mode texte :la a=
valeur saisie est considérée comme une chaîne de caractères. On peut ensuite changer son type, pour 20
le convertir en nombre par exemple (attention cela ne fonctionne que si l’utilisateur a bien saisi un b=
nombre, sinon on déclenche une erreur). Cette conversion est indispensable si on veut ensuite manipuler 13
la valeur numérique. >>> print(a,end="!") # pas de retour à la ligne final
20!>>>
>>> texte = input()
>>> c = 7
123 # on suppose que l’utilisateur saisit 123 en réponse >>> print(a,b,c,sep=";",end=" !\n")
>>> texte
# séparateur ; au lieu d’espace, et on rajoute un ! avant retour chariot
’123’ # la variable texte contient la chaîne de car. ’123’ # final (qu’il faut spécifier avec \n)
>>> texte + 1 # erreur, addition chaîne + entier interdite
20;13;7!
>>> val = int(texte) # conversion de la chaîne en entier
>>>
>>> val + 1 # pas d’erreur, val est bien un entier
124
Alignement de l’affichage Il peut parfois être utile d’aligner les chaînes affichées, notamment
>>> y = int(input()) +1 # en une seule instruction
quand elles sont de tailles différentes. Par exemple imaginons qu’on veuille afficher une liste
d’entiers (colonne de gauche), leur carré (colonne du milieu), et leur cube (colonne de droite).
Message d’instructions. La fonction input() peut recevoir un paramètre optionnel indiquantle L’affichage standard avec l’instruction print(x,x**2,x**3) produira un tableau peu lisible (à
message à afficher. Il est toujours préférable de préciser un message, afin que l’utilisateur gauche ci-dessous).
comprenne pourquoi le programme s’arrête et ce qui est attendu de lui. La méthode rjust() permet de justifier l’affichage d’une chaîne de caractères à droite. Elle
>>> x = float(input("Entrez un nombre : ")) reçoit un argument qui indique la taille de la colonne dans laquelle on justifie à droite (et
Entrez un nombre : # le programme affiche le message et attend donc permet de déduire combien d’espaces il faut insérer à gauche). Ainsi l’instruction
12.3 # on suppose que l’utilisateur répond 12.3 print(str(x).rjust(2), str(x*x).rjust(3),str(x*x*x).rjust(4)) permet de jus-
>>> x + 2 tifier la première colonne (entiers à 1 ou 2 chiffres) sur 2 caractères, la 2e sur 3 caractères, et la 3e
14.3 sur 4 caractères (taille maximale de 4 chiffres). Elle produit un tableau mieux aligné et plus lisible (à
droite ci-dessous).
La somme de 20 et 13 vaut 33. Formatage Une autre manière de formater l’affichage consiste à utiliser l’opérateur % comme
dans les exemples ci-dessous.
Modification de l’affichage Cependant on peut modifier ce comportement par défaut (séparation par
for i in range(7,11): # répétition
des espaces et retour à la ligne final) en spécifiant les paramètres optionnels sep et/ou end. Attention,
ces paramètres fonctionnent uniquement pour la fonction print (pas avec input). On peut aussi print(’%2d’ % i,’%3d’ % i**2) # affichage de l’entier i sur 2 chiffres
insérer manuellement des sauts de ligne en utilisant "\n" et des tabulations avec "\t" # et de son carré sur 3 chiffres
; ce sont des ”caractères spéciaux”. 7 49
8 64
>>> print(a,b,sep=";") # séparateur ; mais on garde retour ligne final 9 81
20;13 10 100
>>> print("a=",a,"b=",b, sep="\n") # retour ligne entre chq arg. + final # affichage du nombre pi (fourni par le module math)
9 10
1.5. Les expressions booléennes 1.5. Les expressions booléennes
>>> print(’%1.7f’ % [Link]) # avec 1 chiffre avant la virgule et 7 après >>> (3 == 1+1) or (a>5) # op. gauche fausse donc il faut évaluer la droite
3.1415927 Traceback (most recent call last):
>>> print(’%1.17f’ % [Link]) # avec 17 chiffres après la virgule File "<stdin>", line 1, in <module>
3.14159265358979312 NameError: name ’a’ is not defined
11 12
1.6. Instructions conditionnelles ’if’ 1.6. Instructions conditionnelles ’if’
Exemples d’instructions qui est exécutée. Le programme continue ensuite à l’instruction suivante. La syntaxe
not( a > 2 or b <= 4 ) équivaut à not(a>2) and not(b<=4) ce qui équivaut à ( a <= 2 ) and ( b > 4 ) not( est la suivante :
a > 2 and b <= 4 ) équivaut à not(a>2) or not(b<=4) ce qui équivaut à ( a <= 2 ) or ( b > 4 )
if condition :
suite d’instructions si vrai
1.4.7 Tables de vérité else :
Une table de vérité permet d’évaluer et de comparer des expressions booléennes. On commence suite d’instructions si faux
par lister toutes les variables et toutes les combinaisons possibles de leurs valeurs (ci-dessous
abrégées T pour True/vrai et F pour False/faux). Plus il y a de variables dans l’expression, et plus il Indentation En Python, c’est l’indentation qui détermine à quel bloc appartient une instruction.
y aura de combinaisons de valeurs possibles : pour n variables, il y a 2**n combinaisons, donc 4 Après la ligne if condition, les lignes suivantes sont indentées à droite pour signifier qu’elles
lignes pour une table de vérité à 2 variables, 8 lignes pour 3 variables, etc. appartiennent à ce bloc if. Si une instruction est alignée à gauche (au même niveau que le if), alors
Par exemple la table de vérité ci-dessous permet d’évaluer le ’ou exclusif’ (noté xor) entre 2 elle marque la fin de l’instruction conditionnelle. Pensez donc toujours à bien indenter votre code
variables a et b, défini comme ’soit a soit b est vraie’ (a or b) ’mais pas les 2 en même temps’ (not (ce qui le rend aussi beaucoup plus lisible).
(a and b)).
Exemple
a b a or b a and b not (a and b) a xor b
V V V V F F x = 5
V F V F V V if x > 0 :
F V V F V V print(x, "est plus grand que 0") # dans le bloc if
F F F F V F print("il est strictement positif") # dans le bloc if
else : # sinon (donc si condition fausse)
TABlE 1.1 – Table de vérité pour le ou exclusif print(x, "est négatif ou nul") # dans le bloc else
print("Fin") # ni dans if ni dans else, toujours exécutée,
# après la fin de l’instruction conditionnelle
1.5 Instructions conditionnelles ’if’ Attention, on peut avoir un if sans else, mais pas l’inverse. Si on ne veut faire aucun
traitement quand la condition est fausse, alors il ne faut pas écrire de else. On ne peut en aucun
En programmation, on peut vouloir effectuer des actions différentes selon qu’une certaine condi- cas écrire un bloc else vide ! Si on ne veut exécuter une instruction que quand la condition est
tion est remplie ou pas. Par exemple : faire un traitement différent selon que la valeur d’une variable fausse, il faut écrire un if avec la négation de cette condition.
est positive ou non.
Dans ce cas, si la condition est vraie, la suite d’instructions est exécutées. Si la condition est fausse, Remarque : la condition d’un bloc elif n’est évaluée que si les conditions précédentes ont échoué.
rien n’est fait, le programme continue après cette instruction. La condition doit être une expression Le programme ne pourra rentrer que dans un seul bloc d’une instruction conditionnelle (le premier
booléenne (par exemple le résultat d’une comparaison entre deux nombres, etc). dont la condition est vraie). Il n’est donc pas nécessaire de spécifier la négation des conditions
Attention à l’indentation, c’est-à-dire le décalage à droite et l’alignement de la suite d’ins- précédentes dans les conditions suivantes. Par exemple :
tructions à l’intérieur du if. C’est l’indentation qui détermine dans quel bloc se trouve une
instruction, et qui indique donc dans quel cas elle doit être exécutée. note = int(input("Quelle est votre note en maths ?"))
13 14
1.6. Instructions conditionnelles ’if’ 1.6. Instructions conditionnelles ’if’
# la version correcte
1.5.5 Imbrication
if note < 10:
print("Vous n’avez pas la moyenne") Remarque : on peut imbriquer les instructions conditionnelles, c’est-à-dire écrire un if dans
# si le premier test échoue, on sait déjà que note>=10 le bloc d’instructions d’un autre if. Cela permet de distinguer des sous-cas, par exemple une fois
# on n’a donc pas besoin de le vérifier dans la condition du elif que je sais que ma variable est positive, je peux vouloir distinguer les valeurs paires ou impaires.
elif note < 12: Attention à l’indentation. A chaque nouveau bloc imbriqué dans le précédent, on décale d’un
print("Pas mal...") cran supplémentaire vers la droite.
elif note < 15:
print("Mention Bien !") Exemple
# si les 2e et 3e tests échouent aussi, on sait que note >= 15, else suffit
print("Testeur de parite")
else:
x = int(input("Entre un entier positif"))
print("Vous avez la bosse des maths !")
if x>=0 : # x est positif
if x%2==0 : # x est positif ET pair
1.5.4 Cas par défaut print(x,"est pair")
Attention : en l’absence d’un bloc else (cas par défaut) il est possible que le programme ne rentre else : # x est positif ET non pair (donc impair)
dans aucun des blocs d’une instruction conditionnelle (si toutes les conditions sont fausses).Il est print(x,"est impair")
donc en général préférable de toujours prévoir un cas par défaut (bloc else). Par exemple : else : # x n’est pas positif (donc negatif)
print("Erreur !",x,"est negatif")
reponse = input("Faites-vous du sport régulièrement ? (oui/non) ")
if reponse==’oui’: 1.5.6 Nombres aléatoires
print("Super, c’est bon pour la santé !")
elif reponse==’non’: Le module random permet de générer des nombres pseudo-aléatoires. Il fournit par exemple
print("Dommage, vous devriez vous y mettre...") les fonctions suivantes qui seront utilisées en TD et TP :
# en l’absence d’un bloc else, le programme n’affichera rien • randint(a,b) : renvoie un entier pseudo-aléatoire entre les bornes a et b (incluses).
# si l’utilisateur répond autrement que par ’oui’ ou ’non’
• randrange(a,b,step) : renvoie un entier pseudo-aléatoire dans range(a,b,step), ce
# il faut rajouter un cas par défaut pour gérer les exceptions
qui permet en plus de spécifier un pas (par défaut 1). Attention la borne supérieure b est ici exclue.
else:
print("Je n’ai pas compris la réponse") • random() : renvoie un réel pseudo-aléatoire entre 0 et 1.
• choice(l) : renvoie un élément au hasard parmi ceux de la liste l.
Exemple : calculer le nombre de racines réelles d’un polynôme du second degré. On sait qu’il ya
3 cas selon que le déterminant est strictement positif, nul, ou strictement négatif. Pour utiliser les fonctions de ce module, il faut l’importer au début du programme avec la commande
: import random puis préfixer les appels aux fonctions par le nom du module. Exemple :
a = 3.2 # coefficient du monome de degre 2 import random
b = 5 # coefficient du monome de degre 1 # nombre entier au hasard entre 1 et 10
c = -7.9 # coefficient du monome de degre 0 i = [Link](1,10)
d = b**2 - 4*a*c # nombre réel au hasard entre 0 et 20
if d>0 : x = 20 * [Link]()
print("Deux racines reelles distinctes")
elif d==0 :
15 16
1.7. La boucle conditionnelle ’while’ 1.7. La boucle conditionnelle ’while’
1.6 La boucle conditionnelle ’while’ Ce programme fonctionne correctement, mais si l’utilisateur entre une valeur B nulle, il n’a
pas de deuxième chance. Comment le modifier afin qu’il continue de demander la valeur de B à
Précédemment, nous avons appris à utiliser les instructions conditionnelles (if-elif-else), l’utilisateur, jusqu’à ce que celle-ci ne soit pas égale à 0 ?
qui permettent d’exécuter une suite d’instructions uniquement si une certaine condition est On pourrait répéter manuellement le même code un certain nombre de fois. Par exemple, pour
vérifiée. On appelle ces instructions des structures de contrôle. En programmation, il existe d’autres donner à l’utilisateur 3 chances d’entrer une valeur correcte, on peut naïvement écrire :
structures de contrôle, les boucles (ou itérations), qui permettent de répéter un ensemble
d’instructions plusieurs fois. En particulier la boucle while permet de répéter un bloc d’instructions a = int(input(‘Donnez la valeur de A : ‘))
tant que une certaine condition (une expression booléenne) reste vraie. On appelle donc cette b = int(input(‘Donnez la valeur de B : ’))
structure une boucle conditionnelle. Comme pour le if, c’est l’indentation des instructions qui if b == 0 :
détermine si elles sont dans la boucle (exécutées tant que la condition est vraie) ou en dehors b = int(input(‘B ne peut etre nul, veuillez reessayer : ’))
(exécutées après la fin de la boucle, quand la condition devient fausse). En Python, la syntaxe if b == 0 :
générale du while est la suivante : b = int(input(‘B ne peut etre nul, veuillez reessayer : ’))
if b == 0 :
while condition :
instruction_1 b = int(input(‘B ne peut etre nul, veuillez reessayer : ’))
instruction_2 if b != 0 :
... print(‘A / B = ‘, a // b)
instruction_n else:
# ici la condition est fausse, on sort de la boucle print(‘Division par 0 impossible’)
Cependant, ce code est très répétitif (ce qui n’est pas bon !) et ne permet de répéter cette action qu’un
Condition de boucle : si la condition est fausse dès le premier essai, alors on n’entre jamais dans nombre limité de fois (ici 3 fois). Ce n’est pas le résultat souhaité. A l’aide du while, onpeut simplement
la boucle et on passe directement à la suite du programme. Au contraire, si la condition reste ré-exprimer le programme comme suit :
toujours vraie, alors on ne sort jamais de la boucle, le programme ne se termine pas, on est coincé
dans une boucle infinie : attention danger ! Pour interrompre un programme qui boucle, il faut a = int(input(‘Donnez la valeur de A : ‘))
taper Ctrl-C au clavier pendant l’exécution. b = int(input(‘Donnez la valeur de B : ’))
while b == 0 :
Utilité : les boucles sont très utiles dans plusieurs cas : pour filtrer les entrées de l’utilisateur ; pour b = int(input(‘B ne peut etre nul, veuillez reessayer : ’))
rejouer un programme ; pour répéter plusieurs fois les mêmes instructions. # sortie de la boucle quand b est different de 0
# maintenant on peut faire la division sans erreur
1.6.1 While pour filtrer print(‘A / B = ‘, a // b)
On a vu qu’un programme pouvait interagir avec l’utilisateur en lui demandant d’entrer des Ce programme redemande la valeur de B tant que celle-ci est égale à 0 (c’est-à-dire jusqu’à ce
valeurs. On a parfois besoin de vérifier que les valeurs entrées par l’utilisateur respectent bien
qu’elle soit non nulle). Si on sort de la boucle, cela veut dire que b n’est plus égal à 0, et on peut alors
certains critères, sous peine que le programme ne fonctionne pas correctement : c’est ce qu’on
effectuer notre division sans re-vérifier sa valeur.
appelle filtrer les entrées.
Ce type de comportement est observé très souvent dans les programmes que nous utilisons
tous les jours. Par exemple, un programme qui nous demande de nous identifier avec un mot de
1.6.2 While pour rejouer un programme
passe (par exemple : Skype), va continuer à afficher la page d’accueil tant qu’on n’a pas rentré les La boucle while peut aussi être utilisée pour répéter un programme un nombre indéterminé de
bons identifiants. fois, selon le choix de l’utilisateur. Par exemple voici un programme qui demande à l’utilisateur un
Considérons un exemple simple, qui demande à l’utilisateur deux entiers positifs A et B, et caractère et affiche son code ASCII.
affiche le quotient de la division de A par B. Pour avoir un résultat correct, nous devons d’abord
vérifier que B est différent de 0. Le programme peut être exprimé de la façon suivante : carac = input("Entre un caractere ?")
code = ord(carac)
a = int(input(‘Donnez la valeur de A : ‘))
print("Le code ASCII de",carac,"est",code)
b = int(input(‘Donnez la valeur de B : ’))
if b != 0 : Si on veut maintenant proposer à l’utilisateur de recommencer avec un nouveau caractère, puis un
print(‘A / B = ‘, a // b) # division entière autre, etc, jusqu’à ce qu’il demande d’arrêter, on peut compléter le programme comme ceci :
else:
print(‘Division par 0 impossible’) play = ’oui’ # on initialise à ’oui’ pour jouer au moins une fois
17 18
1.7. La boucle conditionnelle ’while’ 1.7. La boucle conditionnelle ’while’
Ce programme rentre au moins une fois dans la boucle puisqu’on initialise la variable play à Accumulateurs
la valeur ’oui’, donc le premier test de la condition réussit. Ensuite, après chaque exécution, le
Prenons l’exemple du calcul d’une somme d’entiers. On veut écrire un programme qui calcule et
programme demande à l’utilisateur de dire s’il veut continuer ou pas. Tant que l’utilisateur répond
affiche la somme des 10 premiers entiers strictement positifs (1 à 10). Comme dans l’exemple
’oui’, le programme recommence en demandant un nouveau caractère. Dès que l’utilisateur répond
précédent, nous avons besoin d’une variable compteur (qu’on appellera i), qui va compter de 1 à
’non’ (ou toute autre chaîne que ’oui’) la boucle se termine, et l’instruction suivante est exécutée
10. De plus, nous aurons besoin d’une variable accumulateur (qu’on appellera ‘somme’), qui va
(affichage du message de fin).
accumuler progressivement la somme de toutes les valeurs de i que l’on rencontre. Généralement,
on initialise l’accumulateur à l’élément neutre de l’opération que l’on veut effectuer. Dans notre
1.6.3 While pour répéter, compteur de boucle exemple, l’accumulateur a été initialisé à 0 car c’est l’élément neutre de l’addition (0+x=0).
La boucle while peut également être utilisée pour répéter un bout de code un nombre déterminé
i = 1
de fois. Pour ce faire, on utilise une variable compteur qui s’incrémente à chaque itération. Par
somme = 0 # initialement, la somme est égale à 0
exemple, si on voulait afficher les 10 premières puissances de 2, on pourrait le faire de la manière
while i <= 10 :
suivante :
somme = somme + i # chq valeur de i est ajoutée à somme (accumulation)
i = 0 # notre variable compteur i = i + 1 # ne jamais oublier de mettre à jour le compteur
while i < 10 : # pour 10 valeurs de i, entre 0 et 9 # affichage une seule fois, après la fin de la boucle
print( 2 ** i ) # afficher 2 puissance i print(‘La somme des 10 premiers entiers est : ‘, somme)
i = i + 1 # incrémenter compteur à chaque itération
Drapeaux
Ici, la valeur du compteur i augmente de 1 (on dit que la variable i a été incrémentée) après chaque
affichage. Le premier affichage est effectué lorsque i est égal à 0, puis tout de suite après i est Parfois, l’information qu’on souhaite garder sur notre séquence n’est pas une valeur numérique
incrémenté et prend la valeur 1. Puisque i est toujours inférieur à 10, la boucle continue et l’affichage est mais une propriété. Par exemple, est-ce que tous les nombres parcourus sont impairs ? Dans ce cas,
encore effectué pour i = 1, etc. L’affichage continue donc jusqu’à ce que i devienne supérieur ou égal on peut utiliser une variable booléenne qui est égale à True si la propriété est vérifiée, et à False dans
à 10. En d’autres mots, la variable i va compter de 0 à 9. le cas où cette propriété est fausse. Cette variable, un accumulateur booléen, est aussi appelée
Attention : si on oublie d’incrémenter le compteur, il ne deviendra jamais supérieur ou égal à "drapeau" (ou flag).
10, et la boucle ne s’arrêtera jamais, c’est une boucle infinie (mauvais !).
Il est également possible de compter avec un pas différent de 1. Par exemple, le programme suivant Exemple : on veut lire 10 entiers et vérifier qu’ils sont tous impairs. Pour que cette propriété soit
avance par pas de 2 afin d’afficher tous les entiers positifs pairs inférieurs à 100. vraie, il faut que tous les nombres lus soient impairs. Autrement dit, il faut que : premier nombre est
impair ET deuxieme nombre est impair ET ... Il s’agit donc d’une accumulation utilisant
i = 0
l’opérateur ET (and).
while i < 100 :
Dans cet exemple, la drapeau tous_impairs est initialisé à True, car c’est l’élément neutre de
print(i)
l’opération "and" : si au moins un élément est pair, le drapeau sera égal à False, sinon il restera à
i = i + 2
True. Si le drapeau était une disjonction, c’est-à-dire qu’on utilise un opérateur OU (or) entre les
Le pas peut également être négatif : on parcourt en ordre décroissant. Dans ce cas on initialise le éléments accumulés, alors l’élément neutre serait False : en effet il suffit que l’une des valeurs soit
compteur à la valeur supérieure, et on précise la borne inférieure comme condition de boucle. Par vraie pour que la disjonction soit vraie.
exemple, pour afficher les 10 premiers entiers strictement positifs dans l’ordre décroissant :
i=0
i = 10 # borne supérieure tous_impairs = True
while i > 0 : # condition sur la borne inférieure while i < 10:
print(i) x = int(input(’Entrez un entier:’))
i = i – 1 # décrémenter le compteur tous_impairs = tous_impairs and x % 2 != 0
19 20
1.7. La boucle conditionnelle ’while’ 1.7. La boucle conditionnelle ’while’
i = i + 1 Instruction Break
if tous_impairs:
L’instruction break permet de sortir d’une boucle immédiatement, indépendamment de la condition
print(’Tous les nombres entrés sont impairs’)
du ’while’. Cependant le plus souvent son utilisation n’est pas nécessaire. Par exemple la boucle
else:
suivante se terminera dès que i est égal à 2, et donc n’affichera que les valeurs 0 et 1. Mais il aurait
print(’Au moins un nombre entré n’était pas impair’)
mieux valu changer la condition du while en i<2.
Lorsqu’on utilise l’opérateur ’and’, il suffit que l’une des valeurs ne soit pas impaire pour que
notre drapeau soit faux. Une manière équivalente et plus intuitive d’écrire ce type de programme # avec break # version correcte sans break
est donc de mettre le booléen tous_impairs a False dès qu’on tombe sur une valeur paire. i = 0 i=0
while i < 10: while i<2:
i=0 if i == 2: print(i)
tous_impairs = True break i+=1
while i < 10: print(i)
x = int(input(’Entrez un entier:’)) i = i + 1
if x % 2 == 0:
instructions n’ont pas toujours d’équivalent dans les autres langages de programmation. On essaiera donc autant
tous_impairs = False
que possible d’éviter d’utiliser break et continue.
i = i + 1
if tous_impairs:
print(’Tous les nombres entrés sont impairs’)
else:
print(’Au moins un nombre entré n’était pas impair’)
Une boucle peut s’exécuter indéfiniment lorsque la condition du while est toujours vérifiée
(i.e. ne devient jamais fausse). Cela peut être intentionnel, par exemple en utilisant comme
condition le booléen True. Le programme suivant continue à afficher tout ce que l’utilisateur rentre
au clavier, et ne s’arrête jamais.
while True:
a = input()
print(a)
Mais il arrive également qu’on rentre dans une boucle infinie par erreur, parce qu’on oublie de
mettre à jour les compteurs de boucle. Dans l’exemple suivant on oublie d’incrémenter la valeur de
i, ce qui fait que la condition i < 10 reste tout le temps vraie. Le programme va donc afficher 1 (2 à
la puissance 0) à l’infini, jusqu’à être interrompu par l’utilisateur avec Ctrl-C.
i = 0
while i < 10:
print(2 ** i)
Dans certains cas, break peut aussi être utilisé pour éviter la répétition de code. Par
exemple, supposons que l’on veuille écrire un programme qui lit trois nombres au clavier,
et qui continue à afficher la moyenne des trois nombres jusqu’à ce que cette moyenne soit
inférieure à 10.
21 22
1.7. La boucle conditionnelle ’while’ 1.7. La boucle conditionnelle ’while’
de la boucle de sorte à être sûr d’y rentrer une première fois. On préférera cette solution à celle # si n est un multiple de 2 ou de 3 # on utilise la nég. de la cond.
utilisant break. if n % 2 == 0 or n % 3 == 0: # si n mult. ni de 2 ni de 3
# passer à l’itérat. suivante if n%2!=0 and n%3!=0:
moyenne = 100 # On initialise à une moyenne >= 10 pour être sûr
continue # on l’ajoute à la somme
# qu’on rentre dans la boucle une première fois
# donc ici n mult. ni de 2 ni de 3 somme += n
while moyenne >= 10:
somme = somme + n i += 1
a = int(input())
i = i + 1
b = int(input())
c = int(input())
moyenne = (a + b + c) / 3 1.6.6 Imbrication de boucles
if moyenne >= 10: Il peut y avoir une boucle while parmi les instructions dans un bloc while : on parle alors
print(moyenne) de boucles imbriquées. Prenons comme exemple le programme ci-dessous. Ici, i est le compteur
On peut utiliser le caractère \ pour séparer une expression booléenne trop longue en plusieurs de boucle de la première boucle while (boucle externe) et j celui de la deuxième boucle while
lignes : (boucle interne). (Attention les 2 compteurs doivent être des variables différentes !) La boucle
externe ne passe à l’itération suivante (prochaine valeur de i), qu’après que la boucle interne a fini
a = int(input()) toutes ses itérations. Dans l’exemple, pour chaque valeur de i (de 1 à 3), j comptera de 1 à 2.
while a % 2 != 0 and \
j = j + 1 3, 2
Enfin pour les conditions d’arrêt de boucle, on préférera les intégrer directement dans la condition i = i + 1
de la boucle.
23 24
1.7. La boucle conditionnelle ’while’ 1.7. La boucle conditionnelle ’while’
if condstop :
# version avec break (à ÉVITER) break # réécriture sans break (à PRÉFÉRER)stop=False
while cond: # on teste les 2 conditions while (not condstop) and cond:
instructions instructions
23 24
1.7. La boucle conditionnelle ’while’ 1.7. La boucle conditionnelle ’while’
Exemple d’application : le
programme ci-dessous demande à
l’utilisateur un entier N et affiche
un carré de caractères ’*’ de N
lignes et N colonnes.
N = int(input("Entrez la
valeur de N: "))
i =
0
# compteur de lignes
while i <
N:
# N lignes
j =
0
# compteur d’étoiles
par ligne
23 24
1.8. Les fonctions 1.8. Les fonctions
• Pour qu’il soit plus facile à tester (tester chaque morceau séparément)
Voici le code de cette fonction, qui est à définir au-dessus de votre programme principal. Cette
fonction reçoit 4 arguments : absA, ordA, absB, ordB. Elle renvoie 1 valeur de retour de type
Un exemple du TP
float. Elle n’a pas d’effets de bord (en particulier elle n’affiche rien).
import turtle
def distance(absA, ordA, absB, ordB) :
# fonction qui trace un carre de taille egale a cote
d=(absB-absA)**2 + (ordB-ordA)**2
def carre(cote) :
d=d**(1/2)
i = 1 # compteur du nb de cotes
return d
while i <= 4 :
[Link](cote) On peut alors écrire le programme principal suivant, qui appelle cette fonction en lui passant 4
[Link](90) valeurs pour ses 4 paramètres (dans le même ordre) :
i=i+1
# programme principal # prog. principal
carre(100) # carre de taille 100 print(distance(1, 2, 1, 5))
[Link]() xA=2
[Link](130) yA=3
[Link]() z=distance(xA, yA, 0, 0)
print("Distance de (0,0) à A :", z)
carre(50) # carre de taille 50
On remarque que les valeurs passées en paramètres peuvent être soit des constantes (les entiers 1,
2, 1, 5 dans le premier appel), soit des variables (les variables xA,yA dans le deuxième appel).
1.7.1 Principe d’une fonction On remarque aussi que les variables n’ont absolument pas besoin d’avoir le même nom que celui
Une fonction est une suite d’instructions, encapsulées dans une «boîte», identifiée par un nom ; elle utilisé dans la définition de la fonction. C’est l’ordre qui compte : la première valeur (constante
reçoit zéro, un ou des arguments / paramètres ; elle renvoie zéro, une ou plusieurs valeurs de ou variable) est affectée au premier argument, la 2e valeur au 2e argument, etc. Il faut donc
retour ; et elle crée éventuellement des effets de bord modifiant l’environnement (interactions passer exactement autant de valeurs lors de l’appel que le nombre de paramètres défini pour cette
entrées/sorties, turtle, etc). On peut appeler cette fonction dans un programme pour réutiliser ces fonction.
instructions plusieurs fois, sur des paramètres différents. Cette fonction renvoie une valeur, quand on l’appelle il faut donc faire quelque chose de cette
valeur : soit on l’affiche directement (comme dans le premier appel), mais alors on ne pourra
25 26
1.8. Les fonctions 1.8. Les fonctions
plus réutiliser cette valeur ; soit on la stocke dans une variable (ici dans la variable z pour le 2e 1.7.3 Appel d’une fonction
appel). Attention, la fonction renvoie une valeur, qui est stockée dans la variable d dans le corps de Syntaxe Une fois définie, on peut appeler une fonction par son nom :
la fonction, mais cette variable d est locale à la fonction, elle n’existe pas dans le programme
• Depuis le programme principal
principal. Il faut donc affecter la valeur de retour dans une nouvelle variable, définie dans le
programme principal ou dans la fonction appelante. • Depuis une autre fonction
• Directement depuis l’interpréteur
On peut aussi appeler cette fonction directement depuis l’interpréteur. On peut appeler soit des fonctions qu’on a soi-même définies, soit des fonctions déjà fournies par Python ou par
ses nombreuses librairies (à condition de les avoir importées avant avec import). On a par exemple déjà utilisé des
>>> distance(0, 1, 3, 5) fonctions des modules turtle et random.
La syntaxe pour appeler une fonction est la suivante :
5.0
>>> distance(1,2,4,7) nom_fonction(argument1, argument2, ...)
5.830951894845301
Passage des paramètres Lors de l’appel d’une fonction, les parenthèses doivent contenir exactement autant de
valeurs (constantes ou variables) que la fonction a d’arguments. Ces valeurs sont affectées aux paramètres dans le
1.7.2 Définition d’une fonction même ordre. Si la fonction n’a aucun paramètre, les parenthèses sont vides.
Si on appelle une fonction en lui passant trop de valeurs ou pas assez (par rapport à son nombre de paramètres),
La syntaxe pour définir une nouvelle fonction est la suivante : on déclenche une erreur. Par exemple avec la fonction distance définie ci-dessus avec 4 paramètres :
>>> distance(1,2,3,4,5)
Note : le return est facultatif (dans ce cas la fonction ne renvoie rien), ainsi que les arguments
Traceback (most recent call last):
/ paramètres (une fonction peut ne recevoir aucun paramètre), mais pas les parenthèses (qui sont File "<stdin>", line 1, in <module>
alors vides). TypeError: distance() takes 4 positional arguments but 5 were given
Appel d’une fonction sans paramètres Pour appeler une fonction sans paramètres, il faut quand même
Définition d’une fonction sans paramètres
utiliser des parenthèses (mais vides) pour indiquer qu’on veut exécuter cette fonction. Par exemple avec la fonction
bonjour() définie ci-dessus, directement dans l’interpréteur :
Voici un exemple de fonction sans paramètre (on note qu’il y a des parenthèses vides après le
>>> bonjour()
nom de la fonction, ces parenthèses sont obligatoires). Cette fonction n’a aucune valeur de retour
bonjour
(pas de return), par contre elle a un effet de bord, l’affichage d’un message à l’écran. >>> bonjour
<function bonjour at 0x1048c3048>
def bonjour() :
print("bonjour") Valeur de retour Si une fonction renvoie une valeur de retour, il faut soit utiliser cette valeur immédiatement, ou
l’enregistrer dans une variable pour pouvoir s’en resservir plus tard. Si on se contente d’appeler la fonction, la valeur
Ci-dessous, la fonction n’a pas de paramètre, elle a un effet de bord (affichage du message ’Quel est perdue.
est ton nom ?’ et attente d’une saisie par l’utilisateur), et elle renvoie une valeur.
# definition d’une fonction addition
def addition(x,y):
def demander_nom():
s = x+y
nom=input("Quel est ton nom? ") return s
return nom
# appel de la fonction depuis l’interpréteur
La fonction suivante n’a ni paramètre ni valeur de retour, mais a des effets de bord (dessine un carré >>> addition(3,4) # calcule la somme mais ne sauve pas le résultat
dans la fenêtre turtle). >>> print(s) # s est une variable locale à la fonction
# elle est inconnue ici !
import turtle Traceback (most recent call last):
def carre_standard(): File "<stdin>", line 1, in <module>
i = 1 # compteur du nombre de cotes NameError: name ’d’ is not defined
while i <= 4 :
[Link](100) # option 1 : afficher directement le résultat
[Link](90) print(addition(3,4))
i=i+1 7
27 28
1.8. Les fonctions 1.8. Les fonctions
while i<nb_carres:
# option 2 : enregistrer le résultat carre(cote) # appel a la fonction carre
a = addition(3,4) deplace(cote+10) # appel a la fonction deplace
print(a) i=i+1 # au suivant !
7
# on peut alors le réutiliser Remarque : on peut même appeler une fonction depuis elle-même, c’est alors une fonction récursive (hors programme
b = addition(a,6) de cette UE).
print(b)
13 1.7.4 Différence entre valeur de retour et effets de bord
Valeur None Certaines fonctions n’ont aucune valeur de retour, mais uniquement des effets de bord : elles On a vu qu’une fonction peut renvoyer une ou plusieurs valeurs de retour, ou aucune ; et qu’elle peut avoir des
modifient leur environnement (affichage de valeurs, tracé turtle, etc) mais ne renvoient aucune valeur. On appelle effets de bord, ou pas. Il faut bien distinguer ces deux concepts.
parfois de telles fonctions des procédures. Dans ce cas il est inutile d’affecter leur résultat dans une variable (puisqu’il • Les valeurs de retour sont des valeurs renvoyées par la fonction, avec le mot-clé return. Ces valeurs peuvent
n’y a pas de résultat). Si on le fait quand même, la variable recevra la valeur spéciale None, qui signifie “aucune valeur” (doivent) être utilisées dans la fonction ou le programme qui appelle cette fonction : on peut les afficher, les
: la variable n’a pas de valeur, mais s’affiche comme ”None”. affecter dans des variables, etc.
>>> z=distance(2, 3, 4, 5) # affectation de la valeur dans une variable • Les effets de bord sont des actions réalisées par la fonction qui modifient son environnement, comme d’afficher
>>> print(z) # affichage de la variable contenant la valeur de retour des éléments à l’écran (avec des instructions comme print ou avec les fonctions du module turtle par
2.8284271247461903 exemple). Les éléments affichés à l’écran ne sont pas utilisables dans la fonction ou le programme appelant !
Seul l’utilisateur peut les visualiser à l’écran quand il exécute le programme.
>>> demander_nom() # effets de bord et valeur de retour Regardons la différence sur un exemple. On peut écrire plusieurs fonctions d’addition, qui reçoivent les entiers à
Quel est ton nom? Carole additionner en paramètre ou via une interaction avec l’utilisateur (effet de bord), et qui affichent le résultat (effet de
’Carole’ bord) ou le renvoient (valeur de retour).
>>> name # on n’a pas sauvé le nom, impossible de l’utiliser
Traceback (most recent call last): # Addition de 2 nombres, RENVOIE la somme
File "<stdin>", line 1, in <module> def addition(x,y): # Addition, demande 2 réels, affiche leur somme
NameError: name ’name’ is not defined return x+y def addition_IO():
>>> name = demander_nom() # version correcte x = float(input("x ?"))
Quel est ton nom? Carole # Addition de 2 nombres, AFFICHE la somme y = float(input("y ?"))
’Carole’ def addition_aff(x,y): print(x+y)
>>> print("Bonjour",name) # on peut utiliser le nom print(x+y)
Bonjour Carole
Appel d’une fonction depuis une autre On peut appeler une fonction dans le programme principal, mais
aussi dans le corps d’une autre fonction. Par exemple, en supposant que la fonction carre a été définie précédemment :
29 30
1.8. Les fonctions 1.8. Les fonctions
i=0 # compte les carres déjà tracés
29 30
1.8. Les fonctions 1.8. Les fonctions
Les schémas ci-dessous illustrent les entrées, sorties, et effets de bord de ces fonctions d’addition.
L’appel de ces fonctions depuis un programme principal est donc très différent.
# programme principal
29 30
1.8. Les fonctions 1.8. Les fonctions
addition_aff(13,25) # pas d’affectation ! la fonction affichera 38 L’exécution de ce programme provoque une erreur : NameError : name ’resultat’ is not defined, ce
a = 12 qui signifie que la variable resultat n’est pas définie dans le programme principal, et donc
b = 25 l’instruction qui essaye d’afficher sa valeur échoue. En effet il s’agit d’une variable locale à la
addition_aff(a,b) # la fonction affichera 37 fonction moyenne, qui n’existe pas dans le programme principal. Par contre sa valeur (renvoyée
addition_aff(10,a) # la fonction affichera 22 par la fonction moyenne) a bien été sauvée dans la variable m lors de l’appel de la fonction.
# appel de la fonction qui demande et affiche Variables du programme principal Une variable (de type int, float, bool ou str) définie
addition_IO() # pas d’affectation, pas de paramètres dans le programme principal ne peut pas être modifiée par une instruction qui se trouve à l’intérieur
# la fonction interagira avec l’utilisateur d’une fonction. Cela ne provoque pas d’erreur mais cela crée une nouvelle variable locale portant le
même identificateur (nom) que l’autre variable. Par exemple :
1.7.5 Portée des variables # fonction qui affiche sa variable locale a
Chaque fonction a son propre "lot" de variables auquel elle a le droit d’accéder. Une variable def affiche_a():
créée ou modifiée dans le corps d’une fonction, ou qui contient un argument de la fonction, est a = 1
dite locale, et ne sera pas accessible depuis le programme principal, ni depuis une autre fonction. print(a)
L’utilisation de Python Tutor permet de visualiser les variables définies dans les différents
environnements (frames) : l’environnement global (global frame) correspond au programme # programme principal qui définit une variable a
principal, et chaque fonction a son propre environnement. Ainsi sur la figure ci-dessous on voit a = 2
l’environnement distance frame contenant les variables locales à la fonction distance. # et appelle la fonction ci-dessus
affiche_a() # la fonction affiche la valeur de son a local, soit 1
# affichage de la variable a du programme principal
print(a) # le prog. principal affiche la valeur de son a local, soit 2
Un autre exemple :
def moyenne(x,y):
# calcule la moyenne de x et y
resultat=(x+y)/2
# crée une nouvelle variable test, locale a la fonction
test=resultat
# renvoie la valeur de la variable resultat
return resultat
# programme principal
a=5
b=6
Exemple de variable locale # variable test, locale au programme principal
test=0
def moyenne(x,y):
m=moyenne(a,b)
# calcule la moyenne de x et y, et l’affecte dans une variable locale
print("m =", m) # affiche "m=5.5"
resultat=(x+y)/2
print("test =",test) # affiche "test=0"
# renvoie la VALEUR de cette variable locale
return resultat Ce programme principal initialise à 0 une variable locale test. Ensuite, l’appel à la fonction
moyenne crée une nouvelle variable, aussi nommée test, mais locale à cette fonction. Cet appel
# programme principal ne modifie donc pas la valeur de la variable test du programme principal. L’instruction print
a=5 affiche donc cette valeur non modifiée, c-à-d 0.
b=6
m=moyenne(a,b) # affectation de la valeur de retour dans une variable Variables globales Une variable peut être définie comme globale (mot-clé global) pour pouvoir être
print(m) # affiche 5.5 modifiée partout. Cependant, il faut éviter cette pratique. Cela complique le code inutilement et
print(resultat) # provoque une erreur risque d’entraîner des modifications indésirables ailleurs dans le programme.
31 32
1.8. Les fonctions 1.9. Importation de modules
Attention ! Les variables définies dans le programme principal sont en fait accessibles en • On évitera les variables globales.
lecture seule (on peut les lire mais pas les modifier) depuis l’intérieur d’une fonction, mais ce
comportement est dangereux car très subtil. On ne l’utilisera donc pas (sauf éventuellement pour • On affectera la valeur de retour d’une fonction dans une variable pour pouvoir la réutiliser ; les
des variables "constantes", initialisées une fois au début du programme et jamais modifiées ensuite). On procédures ne renvoient rien et on les appelle donc sans affecter le résultat dans une variable
préférera passer en arguments toutes les valeurs nécessaires. (valeur None).
Par exemple, voici 2 manières de définir une fonction qui décale une chaîne de n tirets. Dans la
première version (incorrecte) on utilise la variable n définie dans le programme principal, que la
fonction peut lire. Cela fonctionne, mais la fonction est mal définie, si elle a besoin de l’information 1.8 Importation de modules
n alors cela devrait être un argument. Dans la deuxième version (correcte), la valeur de n est reçue
en paramètre, et affectée dans la variable n locale à la fonction. C’est la bonne façon de définir cette Un grand nombre de fonctions sont déjà définies en Python, et sont rangées dans des modules sur
fonction. un thème spécifique. Pour utiliser ces fonctions, il faut d’abord importer le module correspondant.
Les syntaxes possibles pour importer un module sont les suivantes :
# version incorrecte, utilise le n du prog. principal en lecture seule
def decalage(s): import nom_module # préfixer ensuite les fonctions par le nom du module
return ("-" * n) + s from nom_module import nom_fonction # importer une fonction specifique,
# pas besoin de préfixer son nom
# depuis l’interpréteur from nom_module import * # importer toutes les fonctions du module,
>>> n=5 # pas besoin de prefixer leurs noms
>>> print(decalage("toto"))
- --- toto import [Link] as plt # renommage module pour simplifier appel
# version correcte, reçoit valeur en param. et l’affecte dans le n local Le mot clé as permet de créer un ’raccourci’ pour appeler les fonctions d’un module. C’est
def decalage(s, n): pratique quand le nom du module est assez long, puisqu’il faut préfixer l’appel de chaque fonction
return ("-" * n) + s par le nom du module. Par exemple pour [Link] ci-dessus, on pourra maintenant
appeler les fonctions en les préfixant uniquement par plt au lieu du nom complet du module.
# depuis l’interpréteur
>>> print(decalage("toto", 5))
Modules utiles Quelques modules intéressants :
- --- toto
>>> print(decalage("maison",10))
• math : regroupe les fonctions mathématiques les plus courantes
maison
• random : génération de nombres pseudo-aléatoires
Variables modifiables Nous avons vu que les variables de types simples définies dans le
programme principal ne sont pas modifiables dans les fonctions appelées. Il y a une exception • turtle : librairie graphique pour l’apprentissage de la programmation
avec les types complexes que nous verrons plus tard. Par exemple le type liste (Chapitre 1.11) [Link]
permet de stocker une liste de plusieurs valeurs. Ces types complexes fonctionnent un peu
différemment des types simples, et en particulier ils peuvent être modifiés par une fonction (ce • os : manipulation de fichiers, dossiers, chemins d’accès, permissions...
sera un nouveau type d’effet de bord).
• Tkinter : interface graphique par défaut
Résumé
• Une variable créée ou modifiée dans une fonction est locale, elle n’existe que dans la 1.9 Chaînes de caractères
fonction.
1.9.1 Type string
• Une variable simple (de type int, float, str ou bool) du programme principal peut être lue
mais ne peut pas être modifiée à l’intérieur d’une fonction. On verra plus tard que c’est Les chaînes de caractères (string en Python) sont un type de données, plus complexe que
différent pour les types complexes (listes ). ceux vus jusqu’à présent. Il s’agit d’un type itérable, c’est-à-dire dont on peut parcourir les valeurs
(ici les différents caractères qui composent la chaîne). On verra d’autres types itérables plus tard
• On passera en argument des fonctions toutes les valeurs nécessaires à leur fonctionnement. (listes, dictionnaires).
33 34
1.10. Chaînes de caractères 1.10. Chaînes de caractères
Syntaxe On a déjà utilisé les chaînes de caractères, notamment dans les fonctions print() et Caractères d’échappement Le caractère pe\rmet d’utiliser des caractères spéciaux dans une chaîne
input(). En Python, il existe 3 syntaxes pour les chaînes de caractères : de caractères :
• Avec des guillemets doubles, ce qui permet d’utiliser des guillemets simples (apostrophes) • \′ est une apostrophe mais ne ferme pas la chaîne de caractères (même si entre apostrophes)
dans le texte :
• \” est une guillemet double, mais il ne ferme pas la chaîne de caractères
print("je m’appelle toto")
• \n : retour à la ligne
• Avec des apostrophes, ce qui permet d’utiliser des guillemets doubles dans le texte :
• \t : tabulation
print(’il a dit "bonjour" en arrivant’)
• \\ : si on veut insérer un caractère \ (’backslash’)
• Avec des guillemets triples, ce qui permet de créer de longues chaînes contenant des
guillemets, des apostrophes, des sauts de ligne... :
Exemples
print("""il m’a dit "je m’appelle toto" puis est parti""")
>>> print("il a dit \"bonjour\" en arrivant")
Exemples il a dit "bonjour" en arrivant
35 36
1.10. Chaînes de caractères 1.10. Chaînes de caractères
>>> ’abc’ < ’a’ Compter On peut aussi vouloir compter le nombre d’occurrences (d’apparitions) d’une chaîne dans
False une autre, avec la fonction count(). Par exemple :
>>> ’abc’ < ’abca’
True >>> "toto".count("o")
>>> ’abc’ < ’z’ 2
True >>> "toto".count("to")
2
>>> ’a’ < ’A’ # les majuscules sont avant dans la table ASCII >>> "toto".count("ot")
False 1
>>> ’A’ == ’a’ # respect de la casse >>> "toto".count("a")
False 0
>>> ’A’ < ’a’
True Test de casse On appelle casse d’une chaîne de caractère le fait de savoir si elle est en majuscules
>>> ’toto’ < ’toto aaa’ (haut de casse) ou en minuscules (bas de casse). Python fournit plusieurs fonctions pour tester ou
True modifier la casse d’une chaîne.
Test d’appartenance Le mot-clé in permet de vérifier si une chaîne (ou un caractère) est inclue Découpage et recollage Il existe différentes fonctions pour découper des chaînes de caractères.
dans une autre. Par exemple : La fonctionlist() fournit la liste de tous ses caractères (espaces compris). La fonction split()
renvoie une liste de chaînes résultant du découpage autour d’un séparateur optionnel fourni en
>>> "a" in "toto" paramètre (ou espace par défaut) ; le séparateur n’apparaît plus dans les éléments. A partir d’une
False liste de chaînes, join() fait l’opération inverse et les recolle ensemble, séparées par une chaîne.
>>> "o" in "toto" Les exemples ci-dessous illustrent la syntaxe de ces fonctions.
True
>>> "to" in "toto" >>> s = "bonjour a tous"
True >>> list(s) # liste des caractères de s
>>> "abc" in "toto" [’b’, ’o’, ’n’, ’j’, ’o’, ’u’, ’r’, ’ ’, ’a’, ’ ’, ’t’, ’o’, ’u’, ’s’]
False >>> [Link]() # découpage de s autour du car. espace (par défaut)
>>> "abc" in "abcd" [’bonjour’,’a’,’tous’]
True >>> [Link](’o’) # découpage autour de la lettre ’o’
>>> "acb" in "abcd" [’b’, ’nj’, ’ur a t’, ’us’]
False >>> ls=[’toto’,’titi’,’abc’,’azerty’] # liste de chaînes de caractères
37 38
1.10. Chaînes de caractères
>>> ’-’.join(ls)
’toto-titi-abc-azerty’
table ASCII
>>> ’’.join(ls) # recollage autour d’une chaîne vide = concaténation
’tototitiabcazerty’
39
1.11. Listes 1.11. Listes
1.10.1 Type liste en Python Une liste est un ensemble ordonné. Cela signifie que les éléments sont dans un ordre donné, et qu’on
peut accéder à un élément à partir de son numéro, qu’on appelle son indice. Les éléments sont
Types simples vs types complexes. On a manipulé jusqu’à maintenant plusieurs types de données indexés (numérotés) à partir de 0, c-à-d que le premier élément a pour indice (position, numéro) 0.
: les entiers (int), les réels (float), les booléens (bool), les chaînes de caractères (str). Il s’agit de En conséquence, pour une liste de n éléments, le dernier élément est à l’indice n-1. Il n’y a pas
types simples, c’est-à-dire ne contenant qu’une seule valeur. Mais on a parfois besoinde d’élément à l’indice n.
manipuler des structures de données plus complexes, comme des listes, des ensembles, des
tableaux à plusieurs dimensions (matrices), etc.
Accès à un élément Pour accéder à l’élément d’indice i d’une liste maliste, on écrit maliste[i].
>>> a = 6 Attention, i doit être strictement inférieur à la taille de la liste, sinon on obtient une erreur. Chaque
>>> type(a) élément est une variable qui peut donc être lue et modifiée.
<class ’int’>
>>> weekend=["samedi","dimanche"]
>>> type(3.5)
>>> weekend[0]
<class ’float’>
’samedi’
>>> type(True)
>>> weekend[1]
<class ’bool‘>
’dimanche’
>>> type(’bonjour’)
>>> weekend[2]
<class ’str’>
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
Listes. En Python, une liste est un ensemble ordonné d’éléments. Elle est nommée par un identi- IndexError: list index out of range
ficateur (comme n’importe quelle variable). Une liste peut grandir (ou se réduire) dynamiquement,
c’est-à-dire qu’on peut y ajouter ou en enlever des éléments : sa taille n’est pas fixe. Une liste peut On peut aussi accéder aux éléments en comptant à partir de la fin de la liste, avec un indice
contenir des éléments de types différents, y compris d’autres listes. Les éléments sont notés entre négatif. L’indice -1 correspond au dernier élément, l’indice -2 à l’avant-dernier, etc. Là aussi, si
crochets, séparés par des virgules. l’indice va trop loin, on déclenche une erreur.
41 42
1.11. Listes 1.11. Listes
43 44
1.11. Listes 1.11. Listes
Ajout d’un seul élément en fin de liste : append Pour ajouter un seul élément e à la fin d’une liste Ajout de plusieurs éléments : extend Pour ajouter plusieurs éléments d’un seul coup à la fin d’une
l, on utilise la fonction [Link](e). Cette fonction modifie directement la liste (effet de bord), liste, on peut utiliser [Link](liste2) qui reçoit une deuxième liste en paramètre,et ajoute
elle ne renvoie rien. Attention donc à ne surtout pas affecter son résultat dans la liste elle-même, tous ses éléments à la fin de la liste. Attention, ce n’est pas l’élément liste2 (un élément de type
sinon on l’écrase ! liste) qu’on ajoute comme un élément de liste, mais bien les éléments qu’elle contient (plusieurs
éléments de type entier). Attention, extend reçoit un seul paramètre, qui doit être une liste (même
>>> Multiple3 = [3, 6, 9]
si elle contient un seul élément).
>>> [Link](12)
>>> Multiple3 # avec extend, les éléments de la 2e liste sont ajoutés dans la 1e
[3, 6, 9, 12] >>> multiple3 = [3,6,9,15,21]
>>> [Link](21) >>> [Link]([24,27])
>>> Multiple3 >>> multiple3
[3, 6, 9, 12, 21] [3, 6, 9, 15, 21, 24, 27]
>>> x = [Link](7) # avec append, c’est la liste qui est ajoutée en fin de liste
>>> Multiple3 # 7 a bien été ajouté en fin de liste >>> multiple3 = [3,6,9,15,21]
[3,6,9,12,7] >>> [Link]([24,27])
>>> x # mais x n’a reçu aucune valeur >>> multiple3
>>> print(x) [3, 6, 9, 15, 21, [24,27]]
None # extend reçoit un seul paramètre de type liste
>>> Multiple3 = [Link](18) # à ne SURTOUT PAS faire >>> [Link](24,27) # erreur, 2 entiers au lieu d’une liste
>>> Multiple3 # on a perdu notre liste Traceback (most recent call last):
>>> print(Multiple3) File "<stdin>", line 1, in <module>
None TypeError: extend() takes exactly one argument (2 given)
>>> [Link](24) # erreur, 24 est un entier et pas une liste
Insertion d’un élément à une position voulue : insert Pour insérer un seul élément, non pas en Traceback (most recent call last):
fin de liste mais à une position donnée, on utilise [Link](index,element). Si l’indice File "<stdin>", line 1, in <module>
donné est trop grand (dépasse la taille de la liste), alors l’élément est inséré en fin de liste (pas TypeError: ’int’ object is not iterable
d’erreur). On peut aussi donner une position négative, qui est alors comptée à partir de la fin de # il faut passer une liste, même si c’est un singleton
la liste. De même, si cet indice négatif est trop petit (avant le début de la liste), l’élément est inséré >>> [Link]([30])
en tout début de liste. Cette fonction modifie directement la liste (effet de bord) mais ne renvoie >>> multiple3
rien. [3, 6, 9, 15, 21, 24, 27, 30]
Remarque : l’insertion d’un élément est plus coûteuse en calcul que append car elle implique de
décaler les autres éléments en mémoire. 1.10.6 Supprimer des éléments
>> multiple3 = [3, 6, 9, 21] Supprimer un élément à une position donnée : pop La fonction [Link](index) retire
>> [Link](3,15) # insérer en position 3 l’élément 15 l’élément présent à la position index et le renvoie. La fonction pop modifie directement la liste (effet
>> multiple3 de bord), et renvoie l’élément supprimé (valeur de retour) ; on peut donc l’affecter dans une variable
[3, 6, 9, 15, 21] pour le récupérer. Si l’indice donné est hors des limites possibles, l’appel déclenche une
45 46
1.11. Listes 1.11. Listes
erreur. Si on ne fournit pas d’indice (paramètre optionnel), la fonction retire et renvoie le dernier Copie/clonage de surface : list() La fonction list() opère une copie de surface : elle crée une
élément de la liste. nouvelle liste contenant les mêmes éléments que la liste initiale. Il s’agira bien de 2 listes distinctes.
Les modifications apportées à une des listes après la copie n’affecteront pas l’autre liste.
>>> multiple3 = [3, 6, 9, 15, 21, 24, 27, 24, 24]
>>> a = [Link](0) liste1=[1,2,3] # création de liste1
>>> a liste3=list(liste1) # copie de liste1 dans liste3
3 [Link]("bip") # modification de liste3
>>> multiple3 >>> liste3
[6, 9, 15, 21, 24, 27, 24, 24] [1, 2, 3, ’bip’]
>>> b = [Link](27) # erreur, indice 27 trop grand >>> liste1 # liste1 n’a pas été modifiée
Traceback (most recent call last): [1, 2, 3]
File "<stdin>", line 1, in <module>
IndexError: pop index out of range
Visualisation On peut utiliser Python Tutor pour bien visualiser ce qui se passe. Sur la première capture
>>> b = [Link]()
d’écran ci-dessous, on a utilisé une simple affectation liste2=liste1, les 2 variables pointent donc
>>> b
vers la même liste : on lui a donné 2 noms. Sur la deuxième capture d’écran on a utilisé list pour faire
24
une copie (de surface) de liste1 dans liste3. Les 2 variables correspondentbien à 2 listes différentes.
>>> multiple3
[6, 9, 15, 21, 24, 27, 24]
>>> multiple3
[6, 9, 15, 21, 24, 27, 24, 24]
>>> [Link](24) # retirer le premier 24 trouvé
>>> multiple3
[6, 9, 15, 21, 27, 24, 24]
>>> [Link](47) # erreur, tentative de supprimer un elt absent
Traceback (most recent call last): FIGURE 1.2 – Copie de surface : liste3 = list(liste1)
File "<stdin>", line 1, in <module>
ValueError: [Link](x): x not in list
1.10.7 Copie et clone de listes Le module copy Le module copy contient plusieurs fonctions génériques permettant de copierdes
variables de différents types. Pour les utiliser il faut d’abord importer ce module avec l’instruction
Renommage de liste Attention : l’opérateur = (affectation) permet juste de donner 2 noms à la
import copy. La fonction [Link]() permet de réaliser une copie de surface. La fonction
même liste. Avec une simple affectation, on donne un deuxième identificateur à la même liste, mais
[Link]() permet de réaliser une copie profonde, ou récursive.
on n’en crée pas de nouvelle. Les deux identificateurs réfèrent toujours à la même liste, et donc les
modifications apportées à une des variables après l’affectation s’appliquent également à l’autre >>> import copy
variable. >>> liste = [1,2,3]
liste1=[1,2,3] # création de liste1 >>> copie = [Link](liste)
liste2=liste1 # liste2 est un autre nom pour liste1 >>> [Link](4)
[Link]("bip") # si on modifie liste2 >>> copie
>>> liste2 [1, 2, 3, 4]
[1, 2, 3, ’bip’] >>> liste
>>> liste1 # on modifie aussi liste1 [1, 2, 3]
[1, 2, 3, ’bip’]
47 48
1.11. Listes 1.12. Boucle inconditionnelle : for
Copie de surface vs copie profonde Si une liste contient d’autres listes, pour la copier correc- Exemple avec oubli de la copie
tement il faut utiliser la fonction deepcopy du module copy, qui va faire une copie profonde,
récursive, c’est-à-dire qu’elle va aussi faire des copies des listes contenues dans la liste copiée. Pour import random
une liste simple, une copie de surface suffit.
def ajoute_random(l):
>>> liste1 """Liste obtenue à partir de l en ajoutant un entier aléatoire entre
[1, 2, 3, [’a’, ’b’, ’c’], 4] 5 et 10"""
>>> surface = [Link](liste1) x=[Link](5,10)
>>> profonde = [Link](liste1) [Link](x)
>>> surface # copie de surface, liste d’indice 3 non clonée return l
[1, 2, 3, [’a’, ’b’, ’c’], 4]
>>> profonde Cette fonction modifie la liste reçue en paramètre (effet de bord) et renvoie la liste modifiée (valeur
[1, 2, 3, [’a’, ’b’, ’c’], 4] de retour). En fait il est inutile de renvoyer la liste, puisqu’on l’a modifiée directement. Ainsi
>>> surface[3].append(’d’) # si on modifie la liste surface[3]
>>> l = [1,2,3]
>>> surface
>>> l2 = ajoute_random(l)
[1, 2, 3, [’a’, ’b’, ’c’, ’d’], 4]
>>> l2
>>> liste1 # alors on la modifie aussi ds liste1 (la même)
[1, 2, 3, 8]
[1, 2, 3, [’a’, ’b’, ’c’, ’d’], 4]
>>> l
>>> profonde[3].append(’e’) # copie profonde/récursive: liste clonée
[1, 2, 3, 8]
>>> profonde # si on modifie profonde[3]
>>> [Link](5)
[1, 2, 3, [’a’, ’b’, ’c’, ’e’], 4]
>>> l
>>> liste1 # on ne modifie pas liste[3]
[1, 2, 3, 8, 5]
[1, 2, 3, [’a’, ’b’, ’c’, ’d’], 4]
>>> l2
[1, 2, 3, 8, 5]
1.10.8 Effets de bord avec les listes
On remarque qu’en fait on a ici donné un deuxième identificateur (l2) pour nommer la même
Une fonction peut modifier une liste passée en argument, indépendamment de sa valeur de retour. liste (l). Et surtout, on a modifié notre liste initiale l alors qu’on ne le souhaitait pas. La version
C’est une nouvelle forme d’effet de bord. Les modifications apportées à la liste dans la fonction sont
correcte de cette fonction est donc la suivante :
conservées après la sortie de la fonction, donc dans le programme appelant. Attention aux effets de
bord non désirés ! Il faut donc éviter qu’une fonction modifie une liste si ce n’est pas prévu, ou alors import random
bien penser à copier la liste initiale avant de la passer en argument si on ne souhaite pas qu’elle def ajoute_random(l):
soit modifiée par la fonction. """Liste obtenue a partir de l en ajoutant un entier aléatoire entre
Par exemple imaginons une fonction qui insère un élément en début et fin de liste. 5 et 10"""
x=[Link](5,10)
ma_liste=list(l) # faire une copie de l
ma_liste.append(x) # modifier la copie et pas l’original
return ma_liste # renvoyer la nouvelle, différente de l’original
Cette nouvelle version de la fonction crée et renvoie une nouvelle liste. La liste reçue en argument
n’est pas modifiée. Il n’y a donc pas d’effets de bord. Attention il faut bien utiliser une fonction
de copie et pas une simple affectation (copie = l), qui ne crée pas de copie et donc conduit à
modifier quand même la liste initiale.
49 50
1.12. Boucle inconditionnelle : for 1.12. Boucle inconditionnelle : for
c-à-d jusqu’à ce que la condition soit fausse. Le plus souvent on ne sait pas combien de fois la Exemples
boucle va se répéter.
Si on connaît à l’avance le nombre de répétition, on peut utiliser le for qui est une boucle # affiche les entiers de 1 à 5 (6 exclus) séparés par une virgule
inconditionnelle. Au lieu de spécifier une condition de répétition, on spécifie directement le for i in range(1,6) :
nombre d’itérations ; la boucle se répète exactement ce nombre de fois. On peut aussi parcourir des print (i,end=",") # affichage de chaque entier suivi d’une virgule
structures itérables (comme les listes) : la boucle se termine alors à la fin du parcours. print() # retour à la ligne à la fin de la sequence
1.11.2 Boucle for pour répéter n fois, fonction range() # affiche les entiers pairs de 0 à 100 (un par ligne)
for i in range(0,101,2) :
Fonction range(). La fonction range(deb, fin, pas) reçoit 3 arguments de type entier, et print(i)
génère une séquence d’entiers compris entre deb inclus et fin exclus, avec le pas choisi. Les
paramètres deb et pas sont optionnels. La borne inférieure deb vaut 0 par défaut, et le pas vaut # affiche les entiers en ordre décroissant de 10 (inclus) à 0 (exclus)
1 par défaut. On peut choisir un pas négatif pour une séquence décroissante d’entiers ; dans ce for i in range(10,0,-1) :
cas fin doit être <= deb, sinon la séquence est vide. print(i)
• range(a) : séquence des entiers dans [0, a[, c’est-à-dire dans [0, a-1] (borne sup exclue)
avec un pas de 1. Boucle while vs for Quand on connaît à l’avance le nombre d’itérations souhaitées, la boucle
• range(b,c) : séquence des valeurs [b, c[, c’est-à-dire dans [b, c-1] (b inclue, c exclue) avec for est beaucoup plus concise. Par exemple, si on veut afficher les entiers de 0 à n.
un pas de 1
# avec un while
• range(e, f, g) : séquence des valeurs [e, f[ avec un pas de g i=0 # initialisation compteur
Remarque : comme les arguments ne sont pas nommés, c’est la position des valeurs qui détermine while i<=n : # condition
à quel argument elles sont affectées (cf chapitre 1.14). On ne peut donc pas omettre la valeur de print(i)
début si on veut préciser le pas. i = i+1 # incrementation compteur
# fin de la boucle quand i depasse n
Utilisation avec for Quand on veut écrire une boucle inconditionnelle avec n répétitions, le plus
simple est donc d’utiliser range(n) pour générer une séquence de n entiers. # avec un for
for i in range(n+1): # range avec n+1 valeurs a partir de 0
for var in range(n) : print(i)
instructions
# fin du for apres exactement n+1 iterations
Plus généralement, si on veut parcourir les entiers entre deb et fin, avec un pas donné, on peut
spécifier les 3 arguments de range.
1.11.3 Parcours de structures itérables
for var in range(deb, fin, pas) :
instructions La boucle for permet aussi de parcourir des structures : listes, chaînes de caractères, etc. Dans
ce cas au lieu d’un compteur de boucle, on utilise une variable qui prend successivement pour
Syntaxe. Comme pour le if et le while, c’est l’indentation des instructions qui détermine si elles sont valeurs tous les éléments contenus dans la structure parcourue (tous les éléments d’une liste, toutes les
dans le bloc for (et donc répétées), ou après la fin du bloc (et donc exécutées seulement quand on sort lettres d’un mot, etc).
de la boucle).
# parcourt les entiers de la liste, calcule la somme
s = 0
Bornes incohérentes En cas d’incohérence dans les bornes du range, la séquence est vide, la
for e in [1, 4, 5, 0, 9, 1] :
boucle est donc ignorée, et l’on passe directement aux instructions suivantes. Par exemple :
s+=e
# de 200 à 210 avec un pas négatif, séquence vide, n’affiche rien print(s) # affichage en sortie de boucle
for k in range(200, 210, -2) : # parcourt les lettres de la liste, affiche 1 par ligne
print(k) for e in ["a", "e", "i", "o", "u", "y"]:
print(e)
# de 110 à 100 avec un pas positif, séquence vide, n’affiche rien # parcourt les lettres du mot, affiche 1 par ligne
for k in range(110,100,2) : for e in "python":
print(k) print(e)
51 52
1.12. Boucle inconditionnelle : for 1.13. Listes avancées
Algorithmes sur les listes La boucle for permet ainsi d’écrire des programmes intéressants pour >>> liste = [1,2,3,4,5]
manipuler des listes : trier une liste pour mettre ses éléments dans l’ordre ; chercher l’élément minimum >>> for i in liste :
ou maximum d’une liste ; compter le nombre d’occurrences d’un éléments donné dans une liste (combien print(i)
de fois il apparaît dans la liste) ; etc. (cf exercices de TD et TP) [Link](i)
# affichage produit
1.11.4 Très important : itération et modification
1
Attention ! Ne jamais modifier la variable de boucle dans le corps d’une boucle for ! Quoi qu’il 3
arrive dans le corps de la boucle, la variable de boucle (celle qui parcourt la séquence ou la structure 5
itérable) prend la valeur suivante (l’entier suivant de la séquence, l’élément suivant de laliste ou
autre structure itérable) à chaque nouvelle étape de la boucle. >>> liste
[2, 4]
Exemple (ce qu’il ne faut pas faire) Ce programme affiche les entiers 1,2,3,4 (un entier par Le comportement obtenu n’est pas ce qu’on attendait : seul un entier sur 2 est affiché et supprimé
ligne), c’est-à-dire qu’il parcourt la séquence générée par range(1,5). La modification de la variable de la liste. En effet, il ne faut jamais modifier la structure (ici la liste) en même temps qu’on la
i dans le corps de la boucle est immédiatement écrasée quand i prend la valeur suivante de la parcourt.
séquence avant de recommencer les instructions du corps de la boucle. Vous pouvez exécuter ce
programme dans Python Tutor pour mieux visualiser.
1.12 Listes avancées
for i in range(1, 5) :
print(i) 1.12.1 Fonction map
i = i*2
La fonction map() permet d’appliquer une fonction à tous les éléments d’une liste, et d’obtenir
la liste de tous les résultats. Le résultat est de type map, qu’il faut convertir en liste. On peut
Exemple corrigé (avec un while) Le programme ci-dessus est mauvais. Il ne faut jamais (jamais !) utiliser en paramètre le nom d’une fonction existante, ou bien une fonction anonyme avec lambda.
modifier le compteur de boucle dans un for. Dans cet exemple il vaudrait mieux écrire une boucle Les fonctions anonymes peuvent aussi servir à combiner plusieurs fonctions. (Voir les exemples ci-
while dans laquelle on peut multiplier i par 2 à chaque itération (il faudra initialiser i avant dessous.)
le while, et la condition du while devra spécifier la valeur maximale souhaitée). Cette version fonctionne
>>> list(map(len,["alex","cyril","elsa"]))
et affiche les entiers 1,2,4 (un par ligne).
[4, 5, 4]
i=1 >>> list(map([Link],[1,4,9,16]))
while i<5: [1.0, 2.0, 3.0, 4.0]
print(i) >>> list(map(lambda x:x**2,[1,4,9,16]))
i=i*2 [1, 16, 81, 256]
>>> list(map(lambda x:int([Link](x)),[1,4,9,16]))
[1, 2, 3, 4]
Exemple corrigé (avec un for) Avec une boucle for, il suffit de se rendre compte qu’on parcourt en
fait les puissances de 2, et d’écrire la version suivante, qui itère sur l’exposant, et affiche les 3 1.12.2 Compréhension de listes
premières puissances de 2 (en partant de puissance 0), donc 1, 2, 4.
Python offre une syntaxe abrégée pour manipuler les listes : la compréhension de listes. C’est
for i in range(3): une syntaxe plus concise pour écrire une boucle for qui crée une liste. Cela permet par exemple
print(2**i) de réécrire la fonction map. Quelques exemples :
53 54
1.14. Fonctions: compléments 1.14. Fonctions : compléments
Exercice bonus : essayer d’écrire les fonctions du TD sur les boucles en un minimum d’ins- Exemple Par exemple cette fonction calcule et renvoie à la fois le quotient et le reste d’une
tructions en utilisant des compréhensions de listes (à éviter en général dans un vrai programme, division entière.
dans un souci de lisibilité).
def division(a,b) :
# renvoie le quotient et le reste
# de la division de a par b
1.13 Fonctions : compléments
quotient=a//b
reste= a%b
1.13.1 Le mot-clé None
return quotient, reste
Procédures Il existe une valeur constante en Python qui s’appelle None. Cela correspond à"rien",
"aucune valeur". Lorsqu’une fonction n’a pas d’instruction return, elle renvoie la valeur None. # programme principal
q,r = division(22,5)
def dit_bonjour(): print("q=", q, "et r=", r)
print("Bonjour!")
print("Bienvenue") 1.14.3 Fonction avec des paramètres optionnels
On a déjà vu plusieurs fonctions avec des paramètres optionnels : print (paramètres sep et
# pas de return Affichage obtenu au lancement du module :
end) ; range (paramètres deb et pas).
# programme Principal Bonjour!
test=dit_bonjour() Bienvenue.
print("Test vaut", test) Test vaut None Syntaxe de la définition d’une fonction à paramètres optionnels Pour rendre un argument
optionnel lors de la définition d’une fonction, il faut ajouter après le nom de l’argument le signe
= suivi de la valeur par défaut. Ci-dessous arg_opt est un argument optionnel de la fonction
Initialisation Le mot-clé None peut aussi servir à initialiser une variable lorsque l’on ne sait pas (valeur par défaut précisée), alors que arg1 n’est pas optionnel (pas de valeur par défaut précisée).
encore précisément quelle valeur on souhaite lui attribuer. Attention, None n’est pas une chaîne
de caractères en Python, donc il ne faut pas de guillemets ! # syntaxe standard d’une fonction avec argument optionnel
def nom_fonc(arg1, arg_opt=valeur_par_defaut):
reponse=None # on n’a pas encore de reponse instructions
while reponse!="non":
x=float(input("Veuillez entrer un nombre:"))
print("Le carré de ce nombre est:", x*x) Exemple La carte de MisterPizza comporte de multiples saveurs de pizzas, chacune pouvant être
reponse=input("Voulez-vous recommencer?") commandée en taille normale au prix de 9 euros, ou en taille maxi au prix de 12 euros. Latrès grande
print("Terminé") majorité des clients choisit des pizzas de taille normale, on veut donc que ce soit la valeur par défaut
si rien n’est précisé. Dans ce cas on peut utiliser un argument optionnel taillequi a pour valeur
par défaut "normale".
1.14.2 Fonction avec plusieurs valeurs de retour
def affiche_pizza(saveur, taille="normale"):
On a vu qu’une fonction pouvait ne rien renvoyer. Une fonction peut aussi renvoyer plus d’une
""" Affiche saveur, taille et prix de la pizza
valeur. Dans ce cas, quand on l’appelle, il faut affecter le retour dans le bon nombre de variables. Par
"""
exemple la fonction ci-dessous calcule et renvoie à la fois le quotient et le reste de la division de a
print("Pizza", saveur, "taille:", taille)
par b. Le programme principal affecte donc son retour dans 2 variables.
if taille=="normale":
prix=9
Syntaxe La syntaxe générale est la suivante : elif taille=="maxi":
prix=12
# Syntaxe (dans le corps de la fonction) pour renvoyer N valeurs print("Prix", prix, "euros.")
return valeur1, valeur2, ... , valeurN
Syntaxe de l’appel d’une fonction à paramètres optionnels Quand on appelle une fonction à
# Syntaxe pour récupérer les N valeurs de retour lors d’un appel paramètres optionnels, on peut préciser une valeur pour le(s) paramètre(s) optionnel(s), ou bien
var1, var2, ... , varN = nom_fonction(arguments) l’omettre et dans ce cas il(s) reçoi(ven)t leur(s) valeur(s) par défaut (spécifiées dans la définition
55 56
1.14. Fonctions: compléments 1.14. Fonctions : compléments
57 58
1.14. Fonctions : compléments 1.15. Dictionnaires
L’exemple de la fonction print En fait, nous avions déjà rencontré une fonction avec des Docstring sur une fonction existante En cas de doute sur le principe d’une fonction existante, vous
arguments optionnels nommés : la fonction print pouvez utiliser la commande help pour afficher sa documentation. Par exemple si on ne se rappelle
plus si les bornes sont incluses lors de la génération d’un entier pseudo-aléatoire.
>>> print("Mon age est", 18)
>>> print("Mon age est", 18, sep="égal à") >>> import random
>>> print("Mon age est", 18, end=".") >>> help([Link])
>>> print("Mon age est", 18, sep=":", end=".") Help on method randint in module random:
randint(a, b) method of [Link] instance
sep et end sont des arguments optionnels de print. Par défaut, sep vaut " " (espace) et end Return random integer in range [a, b], including both end points.
vaut " n" (re\tour à la ligne). Note : sep et end doivent toujours être nommés car la fonction print a
un nombre variable d’arguments non-nommés (les valeurs à afficher), donc on ne peut pas Docstring et Help sur fonction avec paramètres optionnels La documentation affichée pour
déterminer la position de ces arguments. notre fonction précédente montre bien le paramètre optionnel taille et sa valeur par défaut.
>>> help(affiche_pizza)
1.14.4 Utilisation de Docstring
Help on function affiche_pizza in module main :
Une docstring est une chaîne de caractères, encadrée par des triples guillemets, placée au tout début affiche_pizza(saveur, taille=’normale’)
d’une fonction, et qui permet de décrire cette fonction. Affiche saveur, taille et prix de la pizza
help(nom_fonction): Déclaration La syntaxe générale pour déclarer et initialiser un dictionnaire D contenant certaines
Help on function nom_fonction in module nom_module: paires clé-valeur est la suivante :
nom_fonction(argument1, argument2, ...) D = { cle1: valeur1, cle2: valeur2, ..., cleN: valeurN }
docstring de la fonction affichée ici
Exemple On veut créer un dictionnaire contenant la note moyenne de chaque étudiant dans
Exemple Si on spécifie la documentation au moment de la définition de la fonction, l’utilisateur de une certaine matière. Les clés de ce dictionnaire seront les noms des étudiants, et les valeurs seront
notre code pourra alors dans l’interpréteur (ou dans un programme) appeler l’instruction help leurs notes. Chaque valeur (note) est donc associée à un étudiant (clé). Deux étudiants peuvent avoir
pour afficher cette documentation. la même note, mais chaque étudiant ne peut avoir qu’une seule note (on suppose que chaque
prénom est unique dans la classe). Ci-dessous la variable notes est un dictionnaire contenant les
def division(a,b) : notes de deux étudiants. Les chaînes de caractères ‘nathan’ et ‘quentin’ sont les clés de ce
""" Renvoie le quotient et le reste dictionnaire. 12.0 et 15.5 sont les valeurs du dictionnaire. Les éléments du dictionnaire ne sont pas
de la division de a par b """ ordonnés : on n’y accède pas par un numéro (indice, position) mais par leur clé.
quotient=a//b
reste= a%b >>> notes = { ‘nathan’: 12.0, ‘quentin’: 15.5 }
return quotient, reste >>> notes
{’nathan’: 12.0, ’quentin’: 15.5}
>>> help(division)
Help on function division in module main : Types des clés et valeurs Les clés d’un dictionnaire ne peuvent être que de certains types. Dans
division(a, b) ce cours on se limitera aux entiers et aux chaînes de caractères. Par contre comme pour les listes, les
Renvoie le quotient et le reste valeurs dans un dictionnaire peuvent être de n’importe quel type, y compris de type dictionnaire.
de la division de a par b
59 60
1.15. Dictionnaires 1.15. Dictionnaires
pc_tp = { Vérifier l’existence d’une entrée Avant d’accéder à une valeur, on prendra donc l’habitude
‘ram’: 16, # val. de type int de toujours vérifier l’existence de la clé, avec l’opérateur in comme pour les listes. Attention !
‘cpu’: 3.5, # val. de type float L’opérateur in vérifie l’existence d’une clé, et non pas d’une valeur.
‘portable’: False, # val. de type bool
# recherche d’une cle : ok
‘os’: ‘windows’, # val. de type str
‘ports’: [‘usb3.0’, ‘jack’, ‘ethernet’, ‘hdmi’], # val. de type list >>> prix = {‘asus’: 450, ‘alienware’: 1200, ‘lenovo’: 680}
‘carte_graphique’: { # val. de type dict >>> ‘asus’ in prix
‘vram’: 4, True
‘nom’: ‘gtx970’, >>> ‘toshiba’ in prix
‘bus’: 256 False
} # recherche d’une valeur : echec
} >>> 1200 in prix
False
Exemple Si on veut stocker les moyennes des étudiants dans plusieurs matières, on peut avoir un
dictionnaire de dictionnaires, contenant soit un dictionnaire par étudiant (dont les clés seront les 1.14.3 Modification d’un dictionnaire
matières), soit un dictionnaire par matière (dont les clés seront les étudiants). Ajout d’une entrée Pour rajouter une nouvelle entrée (une paire clé :valeur) dans un dictionnaire
# un dico par etudiant existant, il suffit d’utiliser l’opérateur = (affectation) pour associer la valeur à la clé, comme suit. On
notes_e = { peut donc faire une affectation avec une clé qui n’existe pas encore dans le dictionnaire, pour l’y
’nathan’: {’maths’:15, ’info’: 17}, ajouter.
’quentin’: {’info’:13, ’bio’:18} >>> D = {} # crée un dictionnaire vide
} >>> D
# un dico par matière {}
notes_m = { >>> D[‘a’] = 1 # ajout de la nouvelle entrée
’maths’: {’nathan’:15}, >>> D
’info’: {’nathan’:17,’quentin’:13}, {‘a’: 1}
’bio’: {’quentin’:18}
}
Modification d’une entrée Pour modifier une entrée déjà présente dans le dictionnaire (c’est-à-
dire modifier la valeur d’une clé présente dans le dictionnaire), on procède de la même manière, en
1.14.2 Utilisation d’un dictionnaire utilisant aussi l’affectation =. L’ancienne valeur de cette clé est écrasée, remplacée par la nouvelle
Accès aux valeurs L’accès à une valeur du dictionnaire se fait non pas par sa position (indice), mais valeur.
grâce à sa clé. Par exemple dans notre premier dictionnaire de notes, on peut utiliser la chaînede
>>> D
caractères ‘quentin’ (la clé) pour accéder à la valeur qui y est associée dans le dictionnaire notes
{’a’: 1}
(la note de Quentin, 15.5). Les dictionnaires sont aussi appelés listes associatives, car ils permettent
>>> D[‘a’] = 3
d’associer à chaque clé une valeur de type quelconque.
>>> D
>>> notes = {‘nathan’: 12.0, ‘quentin’: 15.5} {‘a’: 3}
>>> notes[‘quentin’] >>> D[’a’]
15.5 3
Erreurs de clé Attention, si on tente d’accéder à une entrée qui n’existe pas dans le dictionnaire, le Suppression d’une entrée L’opérateur del permet de supprimer une association d’un diction-
programme renvoie une erreur de clé (KeyError). naire. Comme pour l’accès aux valeurs, il faut que la clé spécifiée existe, sinon on déclenche une
erreur de clé.
>>> lettres = {‘a’: 103, ‘b’: 8, ‘e’: 150}
>>> lettres[‘k’] # erreur, pas de clé ’k’ dans le dico >>> D = {‘a’: 1, ‘b’: 2, ‘c’: 3}
KeyError: ’k‘ >>> del D[‘a’]
>>> lettres[‘u’] = lettres[‘u’] + 1 # erreur, pas de clé ’u’ >>> D
KeyError: ‘u‘ {‘b’: 2, ‘c’: 3}
61 62
1.15. Dictionnaires 1.15. Dictionnaires
>>> del D[‘j’] # erreur, pas de clé ’j’ 1.14.5 Un exemple détaillé
KeyError: ‘j‘
Dans l’exemple ci-dessus on veut compter chaque lettre dans un mot ou une liste. La fonction
reçoit la lettre à compter et le dictionnaire de compteurs, qu’elle met à jour en conséquence (la
1.14.4 Parcourir un dictionnaire fonction ne renvoie pas le dictionnaire, mais a pour effet de bord de le modifier). Le programme
Itération avec for. La boucle for peut être utilisée pour parcourir toutes les clés d’un dictionnaire (qui principal initialise le dictionnaire de compteurs, parcourt la chaîne de caractères, et appelle cette
permettent d’accéder aux valeurs associées). fonction sur chaque lettre lue.
# affichage des associations clé:valeur, une par ligne # fonction qui reçoit la lettre à compter
for key in D: # et le dictionnaire de compteurs, qu’elle met à jour
print(‘La clé’, key, ‘a pour valeur: ‘, D[key]) # pas de valeur de retour, modif du dico par effet de bord
def vu_lettre(l,cpts):
# affichage des dates d’anniversaire # verification d’existence
dates_naissance={’ingrid’:[12,6,1995],’marc’:[27,8,1996],’brice’:[11,10,1995]} if l in cpts:
# la variable nom parcourt les clés du dictionnaire (les prénoms) # si existe, incrementation
for nom in dates_naissance : cpts[l] = cpts[l] + 1
# date : valeur associée au nom, la liste représentant la date de naiss. else:
date = dates_naissance[nom] # sinon, initialisation
print(nom, ’fetera son anniversaire le’,date[0],’/’,date[1]) cpts[l] = 1
Ce programme affiche les lignes suivantes :
# programme principal
ingrid fetera son anniversaire le 12 / 6 phrase = "bonjour a tous"
marc fetera son anniversaire le 27 / 8 # initialiser un dictionnaire vide de compteurs
brice fetera son anniversaire le 11 / 10 cpts = {}
for lettre in phrase:
Liste des clés et des valeurs La fonction keys() permet d’accéder aux clés d’un dictionnaire, # appel de la fonction sur chaque lettre vue
dans une structure de type dict_keys. De même la fonction values() permet d’accéder aux vu_lettre(lettre,cpts)
valeurs d’un dictionnaire, dans une structure de type dict_values. Ces deux structures ne sont # affichage du dictionnaire de compteurs
pas indexables, mais on peut les convertir en liste avec la fonction list(). Par exemple : print(cpts)
>>> dico = {’a’:1,’b’:0,’c’:0,’d’:0,’e’:1} L’exécution de ce programme affiche le dictionnaire de compteurs ’b’ :1,’o’ :3,’n’ :1,’j’ :1,’u’ :2,’r’ :1,’
>>> dk = [Link]() ’ :2,’a’ :1,’t’ :1,’s’ :1. Seuls les caractères qui ont été rencontrés ont été ajoutés dans le dictionnaire (y
>>> dk compris l’espace).
dict_keys([’a’, ’b’, ’c’, ’d’, ’e’])
>>> dk[1]
1.14.6 Copie de dictionnaires
Traceback (most recent call last):
File "<stdin>", line 1, in <module> Affectation Comme dans le cas des listes, l’affectation d’un dictionnaire vers une variable ne fait
TypeError: ’dict_keys’ object does not support indexing que référencer le même dictionnaire par un nouvel identificateur. Si on modifie l’un, on modifie
>>> [Link]() aussi l’autre.
dict_values([1, 0, 0, 0, 1])
>>> D = {1: 10, 2: 20, 3: 30}
>>> lc = list([Link]()) >>> E = D
>>> lc >>> E[5] = 50
[’a’, ’b’, ’c’, ’d’, ’e’] >>> E
>>> lv = list([Link]()) {1: 10, 2: 20, 3: 30, 5: 50}
>>> lv >>> D
[1, 0, 0, 0, 1] {1: 10, 2: 20, 3: 30, 5: 50}
>>> lv[1]
0 Copie Pour créer une copie de surface d’un dictionnaire, on utilise dict().
63 64
1.16. Introduction aux fichiers 1.16. Introduction aux fichiers
>>> F = dict(D) # création d’une copie de D nommée F Lecture de tout le texte On peut lire en une seule fois tout le contenu du fichier et le stocker
>>> F[6] = 60 # ajout d’une clé dans F dans une chaîne de caractères, qui contiendra le texte entier.
>>> F # F a été modifie
texte = [Link]()
{1: 10, 2: 20, 3: 30, 5: 50, 6: 60}
>>> D # mais pas D
Lecture de toutes les lignes On peut aussi lire en une fois toutes les lignes du fichier et les stocker
{1: 10, 2: 20, 3: 30, 5: 50}
dans une liste de chaînes de caractères (une chaîne par ligne). Après cette instruction, lignes est
>>> G = F # création d’un 2e nom pour le même dico
une liste qui contient toutes les lignes du fichier. On peut y accéder une par une, par exemple
>>> G[7] = 1 # ajout d’une clé dans G
lignes[0] contient la première ligne, etc.
>>> G # G a été modifié
{1: 10, 2: 20, 3: 30, 5: 50, 6: 60, 7: 1} lignes = [Link]()
>>> F # mais F aussi
{1: 10, 2: 20, 3: 30, 5: 50, 6: 60, 7: 1} Lecture itérative par ligne Enfin on peut aussi lire le fichier ligne par ligne de manière itérative,
avec une boucle for. Le programme ci-dessous lit une ligne après l’autre dans le fichier et les affiche
au fur et à mesure. On ne stocke donc jamais l’intégralité du fichier en mémoire, seulement une ligne
1.15 Introduction aux fichiers à la fois.
for ligne in f:
Jusqu’à présent, nous avons utilisé input() et print() pour lire les entrées du programme,
print(ligne) # affiche une ligne du fichier
et afficher les résultats obtenus. Mais parfois, les données d’entrée sont stockées dans un fichier et
on aimerait pouvoir y accéder directement, sans les saisir manuellement au clavier (surtout quand
Exemple Soit le fichier « [Link] » qui contient les entiers suivants (un par ligne) : 15 18 30
il y en a beaucoup, ou quand on teste plusieurs fois un programme). Souvent, il est aussi utile de
55 16 3 12 13. Le programme ci-dessous calcule la somme de ces entiers.
sauvegarder les résultats d’un programme dans des fichiers afin de pouvoir y accéder plus tard (par
ex : sauvegarde d’une partie dans un jeu vidéo). En Python, il est très facile de lire et d’écrire des fichier = open(‘[Link]’) # ouvrir le fichier en lecture
données dans des fichiers. somme = 0 # initialiser la somme
for nombre in fichier: # nombre parcourt les lignes une par une
# nombre est une chaîne, ne pas oublier de la convertir en entier !
1.15.1 Ouverture d’un fichier texte
somme = somme + int(nombre)
Ouvrir un fichier Avant de commencer la lecture d’un fichier, il faut d’abord l’ouvrir. Ouvrir un # après la fin de la boucle de calcul, afficher une seule fois la somme
fichier veut simplement dire que l’on crée une variable qui permet de le manipuler. La fonction print(somme)
open() est utilisée pour ouvrir un fichier. Par exemple pour ouvrir un fichier appelé «[Link]», on # ne pas oublier de fermer le fichier après utilisation
écrit : [Link]()
65 66
1.16. Introduction aux fichiers 1.16. Introduction aux fichiers
Écriture La fonction permettant d’écrire dans un fichier texte est write(). Contrairement à # ouverture en écriture (création si inexistant, écrasement si existe)
print(), la fonction write() ne saute pas de ligne automatiquement. Elle écrit dans le fichier fichier = open(‘[Link]’, ‘w’)
exactement la chaîne de caractères reçue en argument. Pour sauter une ligne dans le fichier, il # 10 itérations pour les 10 puissances
faut écrire un saut de ligne manuellement avec le caractère spécial\n (voir d’autres caractères for i in range(0,10):
spéciaux dans le cours sur les chaînes de caractères). # il faut convertir l’entier en chaîne de caractères
# et passer a la ligne explicitement
[Link](‘ce texte sera écrit dans le fichier’)
[Link](str(2 ** i) + ‘\n’)
[Link](‘\n’) # ceci permet de passer à la ligne
# fin de la boucle, on peut fermer le fichier
[Link]()
Argument de write La fonction write() reçoit exactement un argument, qui doit obligatoire-
ment être une chaîne de caractères. Pour écrire un entier ou une valeur d’un autre type, il faut le convertir
en chaîne de caractères en utilisant str() et la concaténer à la chaîne à écrire.
>>> m = 12
>>> [Link]("m=",m) # on ne peut pas passer plusieurs arguments
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: write() takes exactly one argument (2 given)
>>> [Link](m) # on ne peut pas écrire un entier
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: write() argument must be str, not int
>>> s = "m="+str(m) # creation de la chaine a ecrire
>>> [Link](s) # ecriture : ok
4
Valeur de retour de write La fonction write() renvoie le nombre de caractères effectivement écrits
dans le fichier. Dans l’exemple ci-dessus on a écrit la chaîne "m=12" donc 4 caractères.
1.15.4 Fermeture
Une fois la lecture/écriture terminée, il faut fermer le fichier en utilisant la fonction close().
Une fois fermé, on ne peut plus lire ou écrire dans le fichier.
f = open(‘[Link]’)
# lecture iterative ligne par ligne
for ligne in f:
print(‘une ligne lue :’, ligne)
[Link]()
>>> [Link](’tata’)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: I/O operation on closed file.
67 68