Python
Python
PYTHON
Introduction à Python
https://www.pierre-giraud.com/python-apprendre-programmer-cours/
3
PYTHON
L’idée de ce cors n’est pas simplement de vous présenter les différents éléments
de Python un-à-un mais véritablement de vous expliquer quand et comment
utiliser chaque nouvelle notion afin que vous ayez le plus rapidement une vue
d’ensemble claire pour utiliser les différents éléments de ce langage au bon
moment et à bon escient.
Mon but, à travers ce cours, est de vous amener vers une certaine autonomie et
de faire en sorte que vous soyez capables de réaliser de petits projets Python par
vous même à la fin de celui-ci.
Ce cours est ainsi ouvert à tous : nous commencerons par nous familiariser avec
l’environnement de travail Python avant de présenter des structures simples puis
irons progressivement vers des notions plus complexes.
Vous pouvez à tout moment voir le sommaire du cours sur votre gauche pour
vous repérer et naviguer entre les différentes leçons du cours.
Chaque nouvelle section dispose d’un script illustré par de nombreux exemples.
Dans ce cours Python, nous travaillerons avec l’interpréteur Python en mode
interactif, ce qui signifie que nous taperons les différentes commandes Python
directement dans l’invite de commande ou le terminal. Je vous invite fortement
à faire l’effort de recopier chacun de mes codes vous même car c’est en
pratiquant qu’on apprend le mieux et car c’est comme cela que vous pourrez
vous familiariser le plus vite avec la syntaxe Python et cela rendra le cours
beaucoup plus dynamique pour vous.
Ensuite, nous découvrirons les variables Python, puis les types de données, les
structures de contrôles (conditions et boucles) et les fonctions Python.
Dans un troisième temps, nous nous attaquerons à ce qui fait selon moi le coeur
de Pyhon : l’orienté objet les classes, les instances et les objets.
INTRODUCTION A PYTHON
Python est un langage de programmation créé par Guido Van Rossum. La
première version publique du langage est sortie en 1991. Son nom provient de la
troupe de comiques anglais les Monty Python.
Un ordinateur est une machine dont la fonction principale est de traiter des
données, c’est-à-dire d’exécuter des séries d’instructions pour effectuer
différentes tâches.
En tant que développeurs, nous allons vouloir fournir nos séries d’instructions
aux ordinateurs afin qu’ils exécutent certaines tâches précises dans un certain
ordre.
Pour pallier à ce problème, certaines personnes ont créé ce qu’on appelle des
langages de programmation. Le but premier de tout langage de programmation
est de passer des instructions à l’ordinateur.
Tous les langages de programmation ne sont pourtant pas égaux : certains sont
plus facilement compréhensibles pour nous que d’autres et certains nous
permettent de transmettre uniquement certaines instructions à l’ordinateur.
Python est un langage de programmation dit de “très haut niveau”. Cela signifie
qu’il possède un haut niveau d’abstraction par rapport au langage machine. Pour
le dire très simplement : plus un langage de programmation est de “haut niveau”,
plus sa syntaxe se rapproche de notre langage (l’anglais) plutôt que du langage
machine. Un langage de haut niveau est donc plus facile à comprendre et à
utiliser qu’un langage de plus bas niveau.
d’un programme interprété est généralement plus lente que le même programme
compilé.
Python est modulable et extensible : une fois qu’on connait les bases du langage,
on va pouvoir relativement simplement ajouter de nouvelles fonctions ou
modules pour étendre les possibilités de ce langage.
Python est un langage de programmation conçu dès le départ pour être “full
stack”, c’est-à-dire pour avoir de multiples applications à la différence du PHP
par exemple qui a clairement été imaginé pour fonctionner dans un contexte
Web.
En informatique, les langages évoluent par “version”. Les équipes qui créent un
langage travaillent sans cesse à l’amélioration de celui-ci mais chaque
changement fait sur le langage n’est pas immédiatement intégré au langage ni
disponible au public.
La première grosse mise à jour de Python date de 2000 avec la version Python 2.
Les versions se sont ensuite enchainées normalement avec Python 2.1, 2.2, 2.3,
etc. jusqu’en 2009 avec la sortie de Python 3.
Pour Python 3, l’équipe qui gère l’évolution du Python a fait le choix audacieux
de partir sur de nouvelles bases et de casser la compatibilité avec les anciennes
versions.
Le souci ici est que Python 2.x était déjà très populaire à l’époque et que cela
allait mettre de nombreuses personnes dans l’embarras. L’équipe de Python a
donc fait le choix de conserver deux versions du langage : Python 2.x et Python
3.x et de les faire évoluer de front. Pour être tout à fait précis, la version 3 est la
version dont les fonctionnalités allaient continuer d’évoluer tandis que la version
2 n’allait recevoir que des mises à jour liées à la sécurité.
Python est un langage Open Source. Cela signifie que ses sources et son
interpréteur sont disponibles au public et donc que n’importe qui peut
commencer à développer ses propres programmes Python gratuitement.
L’interpréteur Python
Python est un langage interprété, ce qui signifie qu’on va avoir besoin d’un
programme nommé interpréteur pour convertir nos instructions Python en un
langage compréhensible par notre ordinateur.
Sur cette page, commencez par télécharger la dernière version stable de Python
qui correspond à votre système. L’interpréteur sera parmi les fichiers
téléchargés.
Notez que si vous utilisez un Mac un interpréteur Python devrait déjà être
installé sur votre machine par défaut. Cependant, l’interpréteur pré-installé
risque de correspondre à une ancienne version et nous voulons dans ce cours
travailler avec la dernière version stable du langage (Python 3.7.3 à l’heure de ce
tutoriel).
Une fois que vous avez téléchargé la ressource Python disponible sur le site
officiel, ouvrez la en double cliquant dessus. Un processus d’installation
démarre. Si vous êtes sur Windows, cochez la case “Ajouter Python 3.x au
PATH”. Suivez ensuite le processus d’installation comme pour n’importe quel
autre logiciel.
10
PYTHON
Vous venez d’installer l’interpréteur Python ainsi que d’autres ressources pour
vous aider dans vos développements Python, notamment IDLE et Python
Launcher si vous utilisez un Mac.
Pour exécuter nos scripts Python, il va falloir les passer à l’interpréteur. Pour
cela, nous allons utiliser l’invite de commande (Windows) ou le terminal (Mac).
Une fois que vous êtes dans l’invite de commande ou dans le terminal,
commencez par vérifier que l’interpréteur Python a bien été installé. Pour cela,
tapez la commande python -V (avec un V majuscule) et pressez la touche
Entrée. Si vous êtes sur Mac, Python 2.7 devrait déjà être installé et sera
probablement la version renvoyée. Tapez plutôt la commande python3 -V. La
version de l’interpréteur Python installée devrait vous être renvoyée.
Pour appeler l’interpréteur, tapez simplement python3 (ou python3.7 dans le cas
où il y aurait une ambiguïté) (Mac) ou python (Windows). Si la version de
l’interpréteur vous est renvoyée te que vous voyez un triple chevron $gt;$gt;$gt;,
c’est gagné ! Ce triple chevron est le moyen pour l’interpréteur de nous dire “je
suis prêt à recevoir la prochaine instruction”.
11
PYTHON
A partir de là, nous avons deux options : on va pouvoir soit directement écrire
nos instructions Python dans l’invite de commande ou dans le terminal pour les
exécuter immédiatement, soit créer des fichiers de script Python avec
l’extension .py avec un éditeur de texte et les passer ensuite à l’interpréteur.
Dans l’image ci-dessus, par exemple, j’ai tapé et exécuté une première
instruction Python print() qui sert simplement à afficher un message.
Ecrire son code directement dans l’invite de commande / le terminal est très
pratique pour tester rapidement un code. Cependant, en conditions “réelles”,
c’est-à-dire lorsque vous devrez créer de vrais programmes contenant
potentiellement plusieurs scripts ou lorsque vous voudrez distribuer votre code,
vous stockerez vos instructions dans des fichiers .py que vous allez créer avec
un éditeur de texte ou un IDE.
L’éditeur de texte
Si vous avez décidé de suivre ce tutoriel sur Python, je suppose que vous savez
déjà ce qu’est un éditeur de texte.
Un éditeur de texte nous permet tout simplement d’écrire des lignes de code et
d’enregistrer nos fichiers au bon format.
Pour ma part, dans ce cours, j’utiliserai l’IDE Visual Studio Code de Microsoft
mais vous pouvez utiliser Brackets, Atom, Sublime Text ou encore Komodo si
vous préférez.
Notez par ailleurs qu’il existe certains éditeurs spécialement conçus pour écrire
du code Python dont le célèbre PyCharm notamment.
Nous avons deux choix pour exécuter du code Python : on peut soit écrire
directement notre code dans l’invite de commande (Windows) ou dans le
terminal (Mac) afin que l’interpréteur Python interprète directement notre code
et nous renvoie son résultat ou on peut créer des fichiers Python avec un
ensemble d’instructions à l’intérieur et qu’on va ensuite passer à l’interpréteur.
L’intérêt principal d’un fichier est qu’il peut être sauvegardé et distribué. En
conditions réelles, vous utiliserez donc souvent votre éditeur de texte et créerez
des fichiers Python pour mener à bien des projets.
Dans ce cours, j’écrirai directement dans mon terminal pour vous montrer les
résultats d’instructions simples et nous ne créerons des fichiers que lorsque cela
sera nécessaire. Cependant, pour cette première leçon concrète, je voulais tout
de même vous montrer comment créer un fichier Python et comment exécuter ce
fichier.
Pour créer un fichier Python, nous allons déjà ouvrir notre éditeur de texte,
allons ouvrir un nouveau fichier et enregistrer ce fichier en lui donnant une
extension .py. On peut appeler ce fichier cours.py par exemple et l’enregistrer
dans un dossier Python sur notre bureau.
Ici, on commence par enregistrer notre fichier au format Python avant même
d’écrire un quelconque code car cela va permettre à notre éditeur de reconnaitre
le type de code qu’on souhaite écrire et d nous proposer des fonctionnalités
13
PYTHON
relatives à cela. Par ailleurs, il est possible que votre éditeur vous propose
d’installer des extensions spécifiques Python pour faciliter l’écriture, l’affichage
et le debugging de votre code. Si c’est le cas, n’hésitez pas à les installer.
Ensuite, ajoutez les lignes de code suivantes dans votre fichier (nous allons
expliquer par la suite ce qu’elles signifient) :
Pour exécuter un fichier Python et obtenir le résultat des opérations faites dans
ce fichier, commencez déjà par ouvrir votre invite de commande ou votre
terminal.
Ici, si vous avez bien ajouté Python au PATH, vous n’avez qu’à taper cours.py
pour exécuter le code du fichier “cours.py”. Si votre système possède plusieurs
versions de Python, comme c’est le cas sur Mac, il faudra préciser la version
utilisée : on tapera alors python3 cours.py.
Ensuite, on n’a plus qu’à préciser l’emplacement de notre fichier par rapport à
notre bureau (Desktop), c’est à dire dans notre cas Python/cours.py (Mac) ou
Python\cours.py (Windows) pour exécuter notre fichier, en précisant
éventuellement également une version si plusieurs versions sont installées sur
notre système (python3 Python/cours.py pour Mac).
14
PYTHON
Cette fonctionnalité est très utile lorsqu’on souhaite tester rapidement des bouts
de code ou pour l’apprentissage.
Ensuite, on a plus qu’à écrire nos différentes instructions et à presser Entrée afin
que l’interpréteur les interprète immédiatement.
Chaque langage informatique est basé sur une série de règles et de conventions.
La syntaxe d’un langage définit ses différents éléments et la façon dont on va
pouvoir et devoir les utiliser.
J’aimerais pour le moment m’arrêter sur deux éléments de syntaxe de base que
sont les commentaires et l’indentation ainsi que sur la fonction print().
Les commentaires servent à “commenter” le code : ils vont être ignorés lors de
l’exécution du code (ils n’auront aucun impact sur le script) et vont donc être
totalement transparents pour l’utilisateur final.
Python n’a pas de syntaxe particulière pour écrire des commentaires multi-
lignes. Pour écrire un commentaire sur plusieurs lignes, on insérera un # au
début de chaque ligne.
L’indentation Python
En Python, l’indentation a un tout autre rôle : elle est utilisée par Python pour
définir des blocs de code, c’est-à-dire pour indiquer à l’interpréteur quelle
instruction appartient à quelle autre.
Si on indente mal notre code Python, celui-ci ne s’exécutera tout simplement pas
et Python renverra une erreur. Pas de panique, nous allons apprendre au cours de
ce cours à quelle moment indenter. Cela est cependant relativement évident et ne
devrait pas vous poser de problème : dès qu’il y a une relation de dépendance, il
faudra ajouter un retrait (une fabulation).
16
PYTHON
Dans le code ci-dessus, par exemple, nous avons utilisé une structure
conditionnelle if. Le principe de cette structure est simple : on lui fournit un test
et SI le test est validé, alors on exécute un code. Le code à exécuter dépend du
résultat du test; on effectuera donc un retrait pour mentionner ce code afin que
Python puisse bien s’apercevoir qu’il dépend de la structure conditionnelle.
La fonction print()
Les fonctions sont d’autres éléments de langage que nous étudierons plus tard.
Grosso-modo, une fonction est définie par un nom et une série d’instructions.
Lorsqu’on appelle une fonction (en utilisant son nom et un couple de
parenthèses juste derrière), elle exécute toutes les instructions qu’elle contient.
Les fonctions servent généralement à effectuer une action précise qui peut être
plus ou moins complexe.
Les variables ont une durée de vie limitée (une variable ne vit
généralement que le temps de l’exécution d’un script ou de la fonction qui
l’a définie), ce qui signifie qu’on ne va pas pouvoir utiliser les variables
pour stocker des données de manière pérenne ;
La valeur d’une variable peut varier : les variables peuvent peuvent
stocker différentes valeurs au cours de leur vie (la nouvelle valeur
remplaçant l’ancienne).
Les variables donc être au coeur de nos scripts puisqu’elles vont nous permettre
de conserver des valeurs le temps d’un script et d’effectuer toutes sortes de
manipulations sur ces valeurs en toute simplicité.
Pour créer une variable en Python, on va donc devoir choisir un nom et affecter
une valeur à ce nom, c’est-à-dire stocker une valeur dans notre variable.
Le choix du nom pour nos variables est libre en Python. Il faut cependant
respecter les règles usuelles suivantes :
Notez que les noms de variables en Python sont sensibles à la casse, ce qui
signifie qu’on va faire une différence entre l’emploi de majuscules et de
minuscules : un même nom écrit en majuscules ou en minuscules créera deux
variables totalement différentes.
Pour affecter ou “assigner” une valeur à une variable, nous allons utiliser un
opérateur qu’on appelle opérateur d’affectation ou d’assignation et qui est
19
PYTHON
Le signe = ne sert pas à dire que la valeur est égale au nom de variable ou que la
variable “vaut” cette valeur, il indique simplement qu’on affecte ou qu’on stocke
une certaine valeur dans un conteneur.
D’un point de vue mathématique, par exemple, écrire x = x + 2 n’a aucun sens
car la variable x ne peut être égale qu’à elle même. En informatique, cependant,
c’est tout à fait possible puisque l’opérateur = n’est pas un opérateur d’égalité
mais d’affectation. Ecrire x = x + 2 signifie qu’on affecte une nouvelle valeur à
x qui est égale à l’ancienne valeur de x à laquelle on ajoute 2.
Les variables vont pouvoir stocker différents types de valeurs comme des
nombres, des chaines de caractères, des booléens, et plus encore.
Il est important de connaitre le type de valeur stocké dans une variable car nous
n’allons pas pouvoir effectuer les même opérations avec une variable qui stocke
un nombre ou avec une variable qui stocke une chaine de caractères par
exemple.
20
PYTHON
Nous étudierons les spécificités liées à chaque type de valeur que peut stocker
une variable Python dans la prochaine leçon.
Nous allons pouvoir réaliser toutes sortes d’opérations avec nos variables. La
plus basique d’entre elles consiste à afficher le contenu d’une variable. Pour
afficher la valeur d’une variable Python, il suffit d’écrire son nom, ou
éventuellement d’utiliser la fonction print() en renseignant le nom de la variable
entre les parenthèses/
Comme je l’ai précisé plus haut, l’une des caractéristiques fondamentales des
variables va être de pouvoir stocker différentes valeurs durant sa vie. Ainsi, on
peut tout à fait affecter une nouvelle valeur à une variable. Une variable «
classique » ne va pouvoir stocker qu’une valeur à la fois. En affectant une
nouvelle valeur à une variable, la valeur précédente est ainsi écrasée.
21
PYTHON
Pour comprendre ce code, vous devez savoir qu’ici les instructions sont
exécutées linéairement, c’est-à-dire dans leur ordre d’écriture. On commence
par affecter la valeur 29 à notre variable age et la valeur Pierre à notre variable
prenom, puis on affiche le contenu de ces variables.
Les variables sont des éléments de base présents dans la quasi-totalité des
langages de programmation car elles vont s’avérer indispensables dans de très
nombreuses situations.
Imaginons par exemple qu’on crée un programme qui va effectuer des calculs à
partir d’une valeur qui va lui être envoyée uniquement lorsque ce programme
sera exécuté. Lors de la création du programme, on ne connait pas cette valeur et
cette valeur va pouvoir être différente entre différentes exécutions du
programme.
On va pouvoir indiquer que cette valeur (inconnue pour le moment) devra être
stockée dans telle variable au début du programme et ensuite définir les
différentes opérations qui devront être effectuées sur cette valeur en utilisant le
nom de la variable (qui sera remplacée par sa valeur effective lorsque le
programme s’exécutera).Les types de données ou types de valeurs Python
Dans cette leçon, nous allons définir ce qu’est un type de données et passer en
revue les types de données Python les plus courants et simples à appréhender.
Un “type” de données pour un langage est défini par les manipulations qu’on va
pouvoir faire sur ces données : on va pouvoir effectuer les mêmes opérations sur
chaque donnée d’un même type et des opérations différentes sur différents types
de données.
Prenons un nombre entier par exemple. Il semble tout à fait logique de pouvoir
effectuer des opérations mathématiques de base avec ce nombre : addition,
soustraction, multiplication, etc. En revanche, on ne va pas pouvoir effectuer les
mêmes opérations / manipulations sur un texte, puisque multiplier un texte par
quelque chose par exemple n’a aucun sens.
Python définit de nombreux types de données qu’on va pouvoir stocker dans nos
variables et manipuler à loisir ensuite : nombres entiers, décimaux, complexes,
chaines de caractères, booléens, listes, tuples, dictionnaires, etc.
Dans cette leçon, nous allons nous contenter de passer en revue les types de
données les plus simples à se représenter (nombres, chaines et booléens). Les
autres types de données feront l’objet de leçons séparées.
Le type de données “nombre entier” ou int pour être technique (“int” = “integer”
= entier) couvre tous les nombres entiers positifs ou négatifs. On va pouvoir
effectuer toutes sortes d’opérations arithmétiques avec ce premier type de
23
PYTHON
On peut également stocker des nombres dans des variables et utiliser ces
variables pour effectuer nos calculs. Ici, on commence par définir une variable x
et on lui attribue la valeur 5. On effectue ensuite différentes opérations. Notez
que durant tous ces calculs x continue de stocker 5 puisqu’on n’affecte jamais de
nouvelles valeurs à x. Finalement, on définit une deuxième variable y = 10 et on
demande à Python de calculer x + y, c’est-à-dire de nous donner le résultat de
l’addition des deux valeurs contenues dans x et dans y.
24
PYTHON
Nous allons grosso-modo pouvoir réaliser les mêmes opérations avec des
données de type float qu’avec des données de type int (même si le traitement en
arrière plan va être différent).
Notez qu’on peut également utiliser une syntaxe alternative utilisant des triples
guillemets simples ou doubles pour entourer notre chaine et qui nous dispense
ainsi d’avoir à échapper les apostrophes et les guillemets dans notre chaine :
J’ai dit plus haut que pour définir une chaine de caractères il fallait l’entourer de
guillemets simples ou doubles droits. Réciproquement, toute valeur entourée par
des guillemets simples ou doubles sera considéré par Python comme une valeur
de type str (“str” = “string” = chaine de caractères).
Comme vous pouvez le voir, on n’obtient pas du tout les mêmes résultats
lorsqu’on additionne deux nombres ou lorsqu’on additionne (ou plus exactement
concatène) deux chaines.
Finalement, vous pouvez également remarquer que Python nous renvoie une
erreur lorsqu’on tente d’additionner / de concaténer un entier avec une chaine.
Le dernier type de valeurs simple Python que je tenais à vous présenter est le
type bool (pour “booléen”).
Le type de valeur booléen est un type qui ne contient que deux valeurs qui
servent à représenter deux états. Les deux valeurs sont True (vrai) et False
28
PYTHON
(faux). Attention en Python à bien indiquer des majuscules car dans le cas
contraire Python ne reconnaitra pas ces booléens.
Pour stocker un booléen dans une variable, il ne faut pas utiliser de guillemets :
si on les utilise, ce seront les chaines de caractères “True” et “False” qui seront
stockés et on ne va pas pouvoir effectuer les mêmes opérations.
Les valeurs booléennes sont très utilisées en informatique. Elles sont notamment
très utiles pour valider ou invalider un test et sont au coeur des différentes
structures de contrôle en général.
On voudra souvent s’assurer qu’une variable contient bien une valeur d’un
certain type, notamment pour pouvoir effectuer différentes manipulations avec
cette variable.
Pour connaitre le type de valeur stockée dans une variable, on peut utiliser la
fonction Python type(). On va passer la variable à tester en argument de cette
fonction (c’est-à-dire écrire le nom de la variable entre les parenthèses de la
fonction). La fonction type() va alors tester la valeur contenue dans la variable et
renvoyer le type de cette valeur.
29
PYTHON
Python dispose de nombreux opérateurs qui peuvent être classés selon les
catégories suivantes :
Dans cette leçon, nous allons nous concentrer sur les opérateurs arithmétiques,
les opérateurs de chaines et sur les opérateurs d’affectation.
Nous étudierons les autres types d’opérateurs plus tard dans ce cours, lorsque
nous n aurons besoin pour illustrer certaines notions de Python.
Opérate
Nom
ur
+ Addition
– Soustraction
* Multiplication
/ Division
% Modulo
** Puissance
Division
//
entière
Le résultat de 13//3, par exemple, sera 4 tandis que le résultat de 13%3 sera 1 car
dans le cas d’une division entière 13/3 = 4 avec reste = 1.
Les opérateurs de chaines vont nous permettre de manipuler des données de type
str (chaines de caractères) et par extension des variables stockant des données de
ce type.
Ces opérateurs vont donc nous permettre de réduire la taille de notre code en
nous offrant une écriture simplifiée. Voici la liste des opérateurs d’affectation
supportés par Python et leur équivalent en “version longue” :
Opérate Equivalent
Exemple Description
ur à
= x=1 x=1 Affecte 1 à la variable x
Ajoute 1 à la dernière valeur connue de x et affecte la
+= x += 1 x=x+1
nouvelle valeur (l’ancienne + 1) à x
Enlève 1 à la dernière valeur connue de x et affecte la
-= x -= 1 x=x–1
nouvelle valeur à x
Mutliplie par 2 la dernière valeur connue de x et
*= x *= 2 x=x*2
affecte la nouvelle valeur à x
Divise par 2 la dernière valeur connue de x et affecte
/= x /= 2 x=x/2
la nouvelle valeur à x
Calcule le reste de la division entière de x par 2 et
%= x %= 2 x = x % 2
affecte ce reste à x
Calcule le résultat entier de la division de x par 2 et
//= x //= 2 x = x // 2
affecte ce résultat à x
Elève x à la puissance 4 et affecte la nouvelle valeur
**= x **= 4 x = x ** 4
dans x
Vous pouvez également déjà noter qu’il existe également les opérateurs
d’affectation combinés &=, |=, ^=, >>= et <<= qui vont permettre d’effectuer
des opérations dont nous discuterons plus tard et d’affecter le résultat de ces
opérations directement à une variable.
Jusqu’à présent, nous n’avons stocké qu’une seule valeur à la fois dans nos
variables. Les listes sont un type de données très particulier au sens où elles
représentent des données composées ou combinées. Une liste est en effet par
définition composée d’une suite de valeur ou d’éléments.
Pour définir une nouvelle liste en Python, on va devoir utiliser une paire de
crochets [ ]. Nous allons placer les différents éléments de notre liste dans ces
crochets en les séparant par des virgules. On peut par exemple créer une liste de
5 éléments et la placer dans une variable liste comme ceci :
De plus, vous devez savoir que tous les éléments d’une liste n’ont pas à être du
même type, on va très bien pouvoir créer des listes composées de nombres,
chaines et booléens par exemple :
Note : Si vous avez déjà étudié un langage de script par le passé, les liste doivent
vous faire penser à ce qu’on appelle communément dans ces autres langages des
tableaux. En effet, les listes Python sont très proches des tableaux (numérotés)
qu’on peut retrouver dans de nombreux autres langages.
34
PYTHON
Les listes Python sont par défaut indexées ou indicées. Cela signifie que chaque
valeur d’une liste est lié à un indice qu’on va pouvoir utiliser pour récupérer
cette valeur en particulier.
Pour récupérer une valeur en particulier dans une liste, on va devoir préciser le
nom de la liste suivi de l’indice de cette valeur entre crochets. Notez que les
indices négatifs sont acceptés; dans ce cas on partira de la fin de la liste (l’indice
-1 correspond au dernier élément, -2 à l’avant dernier et etc.).
On va également pouvoir récupérer une tranche de valeurs dans une liste, c’est-
à-dire un ensemble de valeurs qui se suivent. Pour cela, on utilisera le symbole :
entre les crochets avec 0, 1 ou 2 indices autour.
Si on utilise : sans indice, alors une copie superficielle de la liste sera renvoyée.
Si on mentionne un indice avant : mais pas d’indice après, alors une copie
superficielle partielle de la liste de départ sera renvoyée, en commençant à
copier à partir de l’indice donné. Si au contraire on mentionne un indice après :
mais pas d’indice avant, une copie superficielle partielle de la liste de départ sera
renvoyée qui commence au début de la liste et jusqu’à l’indice donné. Enfin, si
deux indice sont mentionnés de part et d’autre de :, la tranche de valeurs
correspondant à ces indices sera renvoyée.
35
PYTHON
Vous devez également savoir que ce qu’on a vu jusqu’ici sur les listes
s’applique également aux chaines de caractères. Les chaînes de caractères
peuvent en effet également être indexées, ce qui signifie qu’on peut accéder aux
caractères par leur position). Cela est logique après tout : les chaines de
caractères sont des “séquences” de caractères tandis que les listes sont des
“séquences” de valeurs.
Comme pour les listes, le premier caractère d’une chaîne possède l’indice 0, le
deuxième l’indice 1 et etc; On va également pouvoir utiliser des indices négatifs
et récupérer des tranches avec :.
Notez qu’il n’existe pas de type distinct pour les caractères en Python : un
caractère est simplement une chaîne de longueur 1.
A la différence des types de données simples comme les chaines qui sont
immuables, les listes sont un type de données altérable ce qui signifie qu’on va
pouvoir altérer leur structure ou modifier leur contenu en ajoutant, supprimant
ou remplaçant des valeurs.
36
PYTHON
En effet, vous devez bien comprendre qu’une fois qu’on définit une valeur
“chaine de caractères” par exemple, celle-ci ne peut plus être modifiée par la
suite. Les seules opération qu’on va pouvoir faire vont être de créer une nouvelle
chaine en concaténant deux chaines d’origine (qui une nouvelle fois ne seront
pas modifiées) ou de remplacer une chaine par une autre valeur en affectant une
nouvelle valeur dans une variable (ce qui a pour effet d’écraser la chaine de
départ).
Nous allons souligner les différences entre les listes et les tuples, voir les cas
d’usage des tuples et apprendre à créer des tuples.
Les chaines de caractères et les listes sont deux types séquentiels de données : ce
sont des données qui sont organisées sous la forme de séquence de caractères ou
de valeurs. Les tuples sont un autre type séquentiel de données.
Les tuples peuvent contenir différents types de valeurs comme des nombres, des
chaines, des listes etc. et même d’autres tuples imbriqués. Illustrons
immédiatement cela :
La grande différence entre un tuple et une liste est qu’un tuple est une donnée
immuable à la différence d’une liste qui est altérable. Cela signifie qu’on ne va
pas pouvoir modifier les valeurs d’un tuple après sa création.
Il va donc être intéressant d’utiliser des tuples plutôt que des listes dans les cas
où on veut s’assurer que les données ne soient pas modifiées dans un
programme.
Notez que dans le cas où on souhaite créer un tuple vide, on utilisera une paire
de parenthèses vides. Si on souhaite créer un tuple avec une seule valeur, alors il
faudra faire suivre cette valeur d’une virgule.
38
PYTHON
Attention ici : il faut bien faire attention à écrire les variables qui vont recevoir
les valeurs du tuple avant le tuple car dans le cas contraire cela ne fonctionnerait
pas.
Les dictionnaires nous laissent une bien plus grande liberté ici puisqu’on va
pouvoir choisir nous mêmes nos clefs (ou index ou indice) et attribuer la clef de
notre choix à chaque valeur à partir du moment où cette clef n’est pas déjà
utilisée dans ce dictionnaire et où la clef est une valeur immuable. La
conséquence de cela est que les valeurs d’un dictionnaire ne sont pas ordonnées
à la différence des valeurs d’une séquence.
Si vous avez des notions en PHP ou dans certains autres langages de script, vous
pouvez retenir que les dictionnaires Python sont l’équivalent des tableaux
associatifs dans ces langages.
Comme vous pouvez le voir dans l’exemple ci-dessus, on utilise une nouvelle
fois le syntaxe avec des crochets pour lire les différentes valeurs de notre
dictionnaire. Pour être tout à fait précis, on passe ici une clef entre crochets pour
récupérer la valeur qui lui est associée.
Pour cela, on va tout simplement utiliser le nom de notre dictionnaire suivi d’un
couple de crochets [ ] en passant une clef entre ces crochets puis affecter une
40
PYTHON
valeur à cette clef. Dans le cas où la clef existe déjà, l’ensemble clef : valeur
n’est pas ajouté mais la valeur originellement liée à la clef est plutôt remplacée
par la nouvelle valeur.
Pour supprimer une paire clef : valeur d’un dictionnaire, nous allons utiliser
l’instruction del (abréviation de “delete” = supprimer en anglais) suivi du nom
du dictionnaire avec la clef de l’élément à supprimer entre crochets comme
ceci :
Une des utilisation les plus courantes des ensembles est de les utiliser pour
supprimer des valeurs doublons à partir d’un autre type de données.
Pour créer un ensemble, nous allons utiliser une paire d’accolades { } en placer
les différents éléments de notre ensemble entre ces accolades en les séparant
avec une virgule.
Notez que pour créer un ensemble vide il faudra utiliser la fonction set() car la
syntaxe { } va créer un dictionnaire vide et non pas un ensemble vide.
1.7.2 Récapitulatif sur les types de données et sur les types composites
Python
Dans cette partie, nous avons étudié des types de données simples et des types
de données composites (des données composées de plusieurs éléments) Python.
Les types de données simples étudiés sont les Nombre (entier, décimaux ou
complexes), les Booléens et les Chaines de caractères. Il sont facile à manier et
il est simple de savoir quand utiliser une type plutôt qu’un autre.
Les types de données composite étudiés sont les listes, les tuples, les
dictionnaires et les ensembles. Il est généralement moins évident de choisir quel
type de données utiliser ici car on a tendance à penser “qu’ils se ressemblent
tous”.
Voici donc un résumé des grandes caractéristiques de ces types et se qui les
différencie :
Nous allons très souvent utiliser les conditions avec des variables : selon la
valeur stockée dans une variable, nous allons vouloir exécuter un bloc de code
plutôt qu’un autre.
La condition if (“si”) ;
La condition if…else (“si…sinon”) ;
La condition if…elif…else (“si…sinon si… sinon”) .
Comme je l’ai précisé plus haut, nous allons souvent construire nos conditions
autour de variables : selon la valeur d’une variable, nous allons exécuter tel bloc
de code ou pas.
Pour pouvoir faire cela, nous allons comparer la valeur d’une variable à une
certaine autre valeur donnée et selon le résultat de la comparaison exécuter un
bloc de code ou pas. Pour comparer des valeurs, nous allons devoir utiliser des
opérateurs de comparaison.
Opérate
Définition
ur
== Permet de tester l’égalité en valeur et en type
!= Permet de tester la différence en valeur ou en type
Permet de tester si une valeur est strictement inférieure à une
<
autre
Permet de tester si une valeur est strictement supérieure à une
>
autre
<= Permet de tester si une valeur est inférieure ou égale à une autre
>= Permet de tester si une valeur est supérieure ou égale à une autre
Notez bien ici que ces opérateurs ne servent pas à indiquer à Python que telle
valeur est supérieure, égale, inférieur ou différente à telle autre valeur.
Lorsqu’on utilise un opérateur de comparaison, on demande au contraire à
Python de tester si telle valeur est supérieure, égale, inférieur ou différente à
telle autre valeur. Python va donc comparer les deux valeurs et toujours
renvoyer un booléen : True si la comparaison est vérifiée ou False dans le cas
contraire.
Vous pouvez retenir ici que c’est cette valeur booléenne renvoyée par le Python
à l’issue de toute comparaison que nous allons utiliser pour faire fonctionner nos
conditions.
On va en fait passer une expression à cette condition qui va être évaluée par
Python. Cette expression sera souvent une comparaison explicite (une
comparaison utilisant les opérateurs de comparaison) mais pas nécessairement.
Nous créons ici deux conditions if. Comme vous pouvez le voir, la syntaxe
générale d’une condition if est if condition : code à exécuter. Pensez bien à
46
PYTHON
indiquer le : et à bien indenter le code qui doit être exécuté si la condition est
vérifiée sinon votre condition ne fonctionnera pas.
Dans notre deuxième if, on demande cette fois-ci à Python de nous dire si le
contenu de x est égal au chiffre 5. Ce n’est pas le cas et donc Python renvoie
False et le code dans ce if n’est donc pas exécuté.
Au final, vous pouvez retenir que toute expression qui suit un if va être évaluée
par Python et que Python renverra toujours soit True, soit False. Nous n’avons
donc pas nécessairement besoin d’une comparaison explicite pour faire
fonctionner un if.
Pour comprendre cela vous devez savoir qu’en dehors des comparaisons Python
évaluera à True toute valeur passée après if à l’exception des valeurs suivantes
qui seront évaluées à False :
Avec la condition if, nous restons relativement limités puisque cette condition
nous permet seulement d’exécuter un bloc de code si que le résultat d’un test
soit évalué à True.
47
PYTHON
Notre deuxième condition fait exactement le même travail mais cette fois si on
compare la valeur de yà 5.
Notez bien ici qu’on n’effectuera jamais de test dans un else car le else est par
définition censé prendre en charge tous les cas non pris en charge par le if.
En effet, nous allons pouvoir ajouter autant de elif que l’on souhaite entre le if
de départ et le else de fin et chaque elif va pouvoir posséder son propre test ce
qui va nous permettre d’apporter des réponses très précises à différentes
situations.
48
PYTHON
Dans cette nouvelle leçon, nous allons aller plus loin avec les conditions Python
est voir comment créer des conditions complexes en utilisant notamment les
opérateurs logiques et les opérations d’appartenance.
Souvent, nous allons vouloir comparer plusieurs valeurs au sein d’une même
condition, c’est-à-dire n’exécuter son code que si plusieurs conditions sont
vérifiées.
Pour faire cela, nous allons pouvoir soit utiliser plusieurs opérateurs de
comparaison, soit les opérateurs logiques, soit imbriquer plusieurs conditions les
unes dans les autres.
Les opérateurs logiques vont nous permettre de créer des conditions plus
puissantes mais dans certains cas il sera plus intéressant et plus rapide
d’imbriquer des conditions.
49
PYTHON
Dans cet exemple, on imbrique deux structures if…else l’une dans l’autre. La
première structure demande à Python de tester si notre variable x contient un
nombre strictement inférieur à 5. Si c’est le cas, on rentre dans le if et on teste
donc la condition du deuxième if. Dans le cas contraire, on va directement au
else de fin.
Les opérateurs logiques vont être principalement utilisés avec les conditions
puisqu’ils vont nous permettre d’écrire plusieurs comparaisons au sein d’une
même condition ou encore d’inverser la valeur logique d’un test.
Opérate
Définition
ur
Les opérateurs logiques and et or vont nous permettre de passer plusieurs tests
pour évaluation à Python. On va par exemple pour tester si une variable x
contient une valeur inférieure à 5 et / ou si y contient une valeur inférieure à 10
au sein d’une même condition.
Dans le cas où on utilise and, chaque expression devra être évaluée à True par
Python pour que le code dans la condition soit exécuté.
50
PYTHON
Dans le cas où on utilise or, il suffit qu’une expression soit évaluée à True par
Python pour que le code dans la condition soit exécuté.
Ici, vous pouvez noter que Python a l’inverse de la plupart des autres langages
possède une syntaxe très logique et très intuitive qui va nous permettre
d’effectuer plusieurs tests dans une condition “comme si” on utilisait un
opérateur logique and en utilisant tout simplement plusieurs opérateurs de
comparaison à la suite.
Finalement, l’opérateur logique not est très particulier puisqu’il nous permet
d’inverser la valeur logique d’un test : si Python renvoie False à l’issue d’une
évaluation par exemple et qu’on utilise l’opérateur not sur cette expression
l’opérateur inversera la valeur renvoyée par Python et la valeur finale passée à la
condition sera True.
Python met à notre disposition deux opérateurs d’appartenant qui vont nous
permettre de tester si une certaine séquence de caractères ou de valeurs est
présente ou pas dans une valeur d’origine.
Comme des valeurs booléennes sont renvoyées, on va tout à fait pouvoir utiliser
ce type d’opérateurs au sein de nos conditions même si ils sont communément
plus utilisés au sein de boucles qu’on étudiera dans la prochaine leçon.
Dans les exemples précédents, nous avons utilisé plusieurs opérateurs différents
dans nos conditions : des opérateurs de comparaisons divers, des opérateurs
logiques, etc.
A partir de là, cependant, il faut commencer à être très rigoureux pour obtenir
des résultats conformes à nos attentes et il va notamment falloir bien connaitre
l’ordre de priorité d’application des différents opérateurs en Python.
Opérateur Description
() Opérateur de groupement
** Elévation à la puissance
==, !=, <, <=, >, >=, in, not in, is, Opérateurs de comparaison, d’appartenance et
is not d’identité
Les boucles vont nous permettre d’exécuter plusieurs fois un bloc de code, c’est-
à-dire d’exécuter un code « en boucle » tant qu’une condition donnée est
vérifiée.
Nous allons ainsi pouvoir utiliser les boucles pour parcourir les valeurs d’une
variable de liste liste ou pour afficher une suite de nombres.
Pour éviter de rester bloqué à l’infini dans une boucle, vous pouvez donc déjà
noter qu’il faudra que la condition donnée soit fausse à un moment donné (pour
pouvoir sortir de la boucle). Selon le type de condition, on va avoir différents
moyens de faire cela. Nous allons voir les plus courants dans la suite de cette
leçon.
On crée ensuite notre boucle while qui va baser sa condition de sortie autour de
la valeur de la variable x.
Littéralement, cette boucle signifie “tant que x stocke une valeur strictement
inférieure à 10, affiche la valeur de x puis ajoute 1 à cette valeur”.
Lors du premier tour dans la boucle, x stocke la valeur 0 qui est bien inférieure à
10. On rentre donc dans la boucle, on affiche la valeur de x et on ajoute 1 à cette
valeur.
La boucle Python for possède une logique et une syntaxe différente de celles des
boucle for généralement rencontrées dans d’autres langages.
En effet, la boucle for Python va nous permettre d’itérer sur les éléments d’une
séquence (liste, chaine de caractères, etc.) selon leur ordre dans la séquence.
On va pouvoir utiliser la fonction range() pour itérer sur une suite de nombres
avec une boucle for.
Cette fonction permet de générer une suite de valeurs à partir d’une certain
nombre et jusqu’à un autre avec un certain pas ou intervalle.
Dans son utilisation la plus simple, nous allons nous contenter de passer un
nombre en argument (entre les parenthèses) de range(). Dans ce cas, la fonction
génèrera une suite de valeurs de 0 jusqu’à ce nombre – 1 avec un pas de 1.
range(5) par exemple génère les valeurs 0, 1, 2, 3 et 4.
servira de point d’arrivée (en étant exclus). range(5, 10) par exemple permet de
générer les nombres 5, 6, 7, 8 et 9.
Les instructions break et continue sont deux instructions qu’on retrouve dans de
nombreux langages et qui sont souvent utilisées avec les boucles mais qui
peuvent être utilisées dans d’autres contextes.
L’intérêt principal des fonctions se situe dans le fait qu’on va pouvoir appeler
une fonction et donc exécuter les instructions qu’elle contient autant de fois
qu’on le souhaite, ce qui constitue au final un gain de temps conséquent pour le
développement d’un programme et ce qui nous permet de créer un code
beaucoup plus clair.
Les fonction prédéfinies sont des fonctions déjà créées et mises à notre
disposition par Python. Dans ce cours, nous avons déjà utilisé des fonctions
prédéfinies comme la fonction print() ou la fonction type() par exemple.
Lorsqu’on a utilisé print() pour afficher des données pour la première fois ou
type() pour connaitre le type d’une donnée, on ne s’est pas posé la question de
ce qu’il se passait en arrière plan.
En fait, ces deux fonctions sont des fonctions complexes et qui contiennent de
nombreuses lignes d’instructions leur permettant d’accomplir une tâche précise :
l’affichage d’un résultat ou la détermination du type d’une valeur en
l’occurence.
Cette complexité nous est cachée : nous n’avons qu’à appeler nos fonctions pour
qu’elles fassent leur travail et n’avons pas à écrire la série d’instructions qu’elles
contiennent à chaque fois et c’est tout l’intérêt des fonctions.
memoryview
abs() delattr() hash() set()
()
enumerate( staticmethod(
bin() input() oct()
) )
isinstance(
breakpoint() exec() ord() sum()
)
issubclass(
bytearray() filter() pow() super()
)
classmethod(
getattr() locals() repr() zip()
)
En plus des fonction prédéfinies, Python nous laisse la possibilité de définir nos
propres fonctions. Ces fonctions ne seront bien évidemment disponibles et
utilisables que dans l’espace où elles ont été définies, c’est-à-dire uniquement au
sein de nos scripts et non pas pour l’ensemble des développeurs utilisant Python.
61
PYTHON
Les fonctions vont aussi être de très bons outils d’abstraction lorsqu’on voudra
distribuer notre code : on préférera souvent fournir des fonctions à utiliser aux
autres développeurs plutôt que de les laisser se débrouiller avec des séries
d’instructions “sauvages”.
Pour définir une nouvelle fonction en Python, nous allons utiliser le mot clef def
qui sert à introduire une définition de fonction. Ce mot clef doit être suivi du
nom de la fonction, d’une paire de parenthèses au sein desquelles on pourra
fournir une liste de paramètres (nous reviendrons là dessus plus tard) et de : pour
terminer la ligne comme ceci def ma_fonction():.
Le nom d’une fonction Python doit respecter les normes usuelles concernant les
noms : un nom de fonction doit commencer par une lettre ou un underscore et ne
contenir que des caractères alphanumériques classiques (pas d’accent ni de
cédille ni aucun caractère spécial).
Notez que les noms de fonctions sont sensibles à la casse en Python, ce qui
signifie que les fonctions ma_fonction(), Ma_fonction(), ma_FONCtion() et
MA_FONCTION() par exemple seront des fonctions bien différentes pour
Python.
Nous allons ensuite placer la liste des différentes instructions de notre fonction à
la ligne suivant sa définition et en les indentant par rapport à la définition afin
que Python comprenne que ces instructions appartiennent à notre fonction.
Notez que la première instruction d’une fonction peut être une chaîne de
caractères littérale qui sera alors utilisée comme chaine de documentation de la
fonction.
Nous avons ici défini nos deux premières fonctions. Ces fonctions ne sont pas
très utiles ici : elles se contentent simplement d’exécuter une fonction print()
mais c’est déjà un bon début !
Maintenant que nos fonctions sont créées, nous allons devoir les appeler pour
exécuter le code qu’elles contiennent. Pour cela, nous allons utiliser leur nom
suivi d’un couple de parenthèses. On va pouvoir appeler nos fonctions autant de
fois qu’on le souhaite dans notre script : c’est tout l’intérêt des fonctions !
Les fonctions que nous avons créées ci-dessus se contentent d’exécuter toujours
la même fonction print() et donc de renvoyer toujours le même message.
Elles ne sont pas très utiles en l’état. Un autre aspect fondamental des fonctions
est qu’elles vont pouvoir accepter des informations qui viennent de l’extérieur,
c’est-à-dire qui sont externes à leur définition et qui vont les amener à produire
des résultats différents. Souvent même, les fonctions vont avoir besoin qu’on
leur passe des informations externes pour fonctionner normalement.
C’est par exemple le cas des fonctions print() et type() : ces deux fonctions
permettent d’afficher un message et de déterminer le type d’une donnée. Pour
afficher un message, print() va avoir besoin qu’on lui passe les données qu’elle
doit afficher. De même, type() va avoir besoin qu’on lui fournisse la donnée
dont elle doit déterminer le type.
63
PYTHON
Ces informations dont vont avoir besoin certaines fonctions pour fonctionner et
qu’on va passer à nos fonctions entre le couple de parenthèses sont appelées des
arguments ou des paramètres.
Expliquons ce code. On crée une nouvelle fonction bonjour() dont le rôle est
d’afficher “Bonjour” suivi du prénom de quelqu’un. Pour que cela fonctionne, il
va falloir lui passer un prénom lorsqu’on appelle notre fonction en argument de
celle-ci.
Ici, je vous rappelle que le mot qu’on utilise comme paramètre lors de la
définition de la fonction sera remplacé par la valeur passée en argument lors de
l’appel à la fonction. On va donc utiliser notre paramètre dans print() afin que
cette fonction affiche bien “Bonjour” suivi d’un prénom.
Le code de notre fonction n’est cependant pas très optimisé ici : en effet, on
utilise de la concaténation dans print() or la concaténation ne va fonctionner que
si la valeur passée est bien une chaine de caractères. Si on passe un un chiffre en
argument de bonjour(), Python renverra une erreur.
Dans la leçon précédente, nous avons défini ce qu’étaient des paramètres et des
arguments. Nous avons créé une fonction bonjour() qui avait besoin qu’on lui
passe un argument pour fonctionner comme ceci :
65
PYTHON
Dans certaines situations, nous voudrons créer des fonctions plus flexibles qui
pourront accepter un nombre variable d’arguments. Cela peut être utile si on
souhaite créer une fonction de calcul de somme par exemple qui devra
additionner les différents arguments passés sans limite sur le nombre
d’arguments et sans qu’on sache à priori combien de valeurs vont être
additionnées.
En Python, il existe deux façons différentes de créer des fonctions qui acceptent
un nombre variable d’arguments. On peut :
3.2.2 Préciser des valeurs par défaut pour les paramètres d’une fonction
On va déjà pouvoir préciser des valeurs par défaut pour nos paramètres. Comme
leur nom l’indique, ces valeurs seront utilisées par défaut lors d’un appel à la
fonction si aucune valeur effective (si aucun argument) n’est passée à la place.
Utiliser des valeurs par défaut pour les paramètres de fonctions permet donc aux
utilisateurs d’appeler cette fonction en passant en omettant de passer les
arguments relatifs aux paramètres possédant des valeurs par défaut.
On va pouvoir définir des fonctions avec des paramètres sans valeur et des
paramètres avec des valeurs par défaut. Attention cependant : vous devez bien
comprendre qu’ici, si on omet de passer des valeurs lors de l’appel à la fonction,
Python n’a aucun moyen de savoir quel argument est manquant. Si 1, 2, etc.
arguments sont passés, ils correspondront de facto au premier, aux premier et
deuxième, etc. paramètres de la définition de fonction.
66
PYTHON
Pour cette raison, on placera toujours les paramètres sans valeur par défaut au
début et ceux avec valeurs par défaut à la fin afin que le arguments passés
remplacent en priorité les paramètres sans valeur.
Si on souhaite s’assurer que les valeurs passées à une fonction vont bien
correspondre à tel ou tel paramètre, on peut passer à nos fonctions des
arguments nommés. Un argument nommé est un argument qui contient le nom
d’un paramètre présent dans la définition de la fonction suivi de la valeur qu’on
souhaite passer comme ceci : argument = valeur.
On va pouvoir passer les arguments nommés dans n’importe quel ordre puisque
Python pourra faire le lien grâce au nom avec les arguments attendus par notre
fonction. Notez cependant qu’il faudra ici passer les arguments nommés en
dernier, après les arguments sans nom. Par ailleurs, aucun argument ne peut
recevoir de valeur plus d’une fois. Faites donc bien attention à ne pas passer une
valeur à un argument sans le nommer puis à repasser cette valeur en le nommant
par inattention.
67
PYTHON
La syntaxe *args (remplacez “args” par ce que vous voulez) permet d’indiquer
lors de la définition d’une fonction que notre fonction peut accepter un nombre
variable d’arguments. Ces arguments sont intégrés dans un tuple. On va pouvoir
préciser 0, 1 ou plusieurs paramètres classiques dans la définition de la fonction
avant la partie variable.
68
PYTHON
Ici, on utilise une boucle for pour itérer parmi les arguments : tant que des
valeurs sont trouvées, elles sont ajoutées à la valeur de s. Dès qu’on arrive à
court d’arguments, on print() le résultat.
Dans cette exemple, j’utilise la méthode Python items() dont le rôle est de
récupérer les différentes paires clefs : valeurs d’un dictionnaire. Nous
reparlerons des méthodes lorsque nous aborderons l’orienté objet. Pour le
moment, vous pouvez considérer qu’une méthode est l’équivalent d’une
fonction.
Les syntaxes *args et **kwargs peuvent être utilisées pour réaliser les
opérations inverse de celles présentés ci-dessus, à savoir séparer des données
composites pour passer les valeurs ou éléments de ces données un à un en
arguments des fonctions.
On, utilisera la syntaxe *args pour séparer les arguments présents dans une liste
ou un tuple et la syntaxe **kwargs pour séparer les arguments présents dans un
dictionnaire et fournir des arguments nommés à une fonction.
69
PYTHON
Jusqu’à présent, nos fonctions n’ont fait qu’afficher leur résultat après qu’on les
ait appelées. En pratique, cette façon de procéder est rarement utilisée et ceci
pour deux raisons : d’une part, nous n’avons aucun contrôle sur le résultat
affiché puisque celui est affiché dès que la fonction a fini de s’exécuter et
ensuite car nous ne pouvons pas utiliser ce résultat pour effectuer de nouvelles
opérations.
Pour cela, créons par exemple une fonction très simple qui renvoie la différence
entre deux nombres.
Ici, on utilise return afin de demander à notre fonction de retourner son résultat.
On stocke ensuite ce résultat dans une variable x dont on pourra se resservir
dans la suite du script.
Une fonction ne peut retourner qu’une donnée à la fois. Cependant, Python met
à notre disposition des types de données composites comme les listes ou les
tuples par exemple.
Pour cela, on va préciser les différentes valeurs que doit retourner return en les
séparant par des virgules. Les valeurs retournées seront retournées dans un tuple.
71
PYTHON
Nous avons vu dans les leçon précédente qu’une fonction pouvait exécuter une
autre fonction, par exemple dans le cas où on demande à une fonction d’exécuter
une fonction print() pour afficher une valeur.
Vous devez savoir qu’une fonction peut également s’appeler elle même dans son
exécution : c’est ce qu’on appelle la récursivité. Lorsqu’on définit une fonction
récursive, il faudra toujours faire bien attention à fournir une condition qui sera
fausse à un moment ou l’autre au risque que la fonction s’appelle à l’infini.
Ici, la condition de sortie de notre fonction est atteinte dès que la valeur passée
en argument atteint ou est inférieure à 1. Expliquons comment fonctionne cette
fonction en détail. Si on passe une valeur inférieure ou égale à 1 à notre fonction
au départ, on retourne la valeur 1 et la fonction s’arrête.
Par définition, toute fonction est censée renvoyer une valeur. Une fonction qui
ne renvoie pas de valeur n’est pas une fonction : on appelle cela en
programmation une procédure.
En Python, en fait, même les fonctions sans instruction return explicite renvoient
une valeur qui est None. Le valeur None est une valeur qui correspond justement
à l’absence de valeur. Cette valeur sert à indiquer “il n’y a pas de valeur”.
L’interpréteur Python l’ignore lorsque c’est la seule valeur qui est renvoyée
mais elle existe tout de même et c’est la raison pour laquelle on appelle les
fonctions qui ne possèdent pas de return explicite des fonctions en Python.
En Python, nous pouvons déclarer des variables n’importe où dans notre script :
au début du script, à l’intérieur de boucles, au sein de nos fonctions, etc.
Le terme de “portée des variables” sert à désigner les différents espaces dans le
script dans lesquels une variable est accessible c’est-à-dire utilisable. En Python,
une variable peut avoir une portée locale ou une portée globale.
Les variables définies dans une fonction sont appelées variables locales. Elles ne
peuvent être utilisées que localement c’est-à-dire qu’à l’intérieur de la fonction
qui les a définies. Tenter d’appeler une variable locale depuis l’extérieur de la
fonction qui l’a définie provoquera une erreur.
Cela est dû au fait que chaque fois qu’une fonction est appelée, Python réserve
pour elle (dans la mémoire de l’ordinateur) un nouvel espace de noms (c’est-à-
dire une sorte de dossier virtuel). Les contenus des variables locales sont stockés
dans cet espace de noms qui est inaccessible depuis l’extérieur de la fonction.
Cet espace de noms est automatiquement détruit dès que la fonction a terminé
son travail, ce qui fait que les valeurs des variables sont réinitialisées à chaque
nouvel appel de fonction.
Pour le dire très simplement : une fonction va pouvoir utiliser la valeur d’une
variable définie globalement mais ne va pas pouvoir modifier sa valeur c’est-à-
dire la redéfinir. En effet, toute variable définie dans une fonction est par
définition locale ce qui fait que si on essaie de redéfinir une variable globale à
l’intérieur d’une fonction on ne fera que créer une autre variable de même nom
que la variable globale qu’on souhaite redéfinir mais qui sera locale et bien
distincte de cette dernière.
Cela est possible en Python. Pour faire cela, il suffit d’utiliser le mot clef global
devant le nom d’une variable globale utilisée localement afin d’indiquer à
Python qu’on souhaite bien modifier le contenu de la variable globale et non pas
créer une variable locale de même nom.
75
PYTHON
Vous trouverez dans la suite de cette leçon quelques définitions de fonctions qui
pourront vous servir par la suite.
Nous allons ici étudier les fonctions range(), round(), sum(), min() et max().
La fonction sum() permet de calculer une somme. On peut lui passer une liste de
nombres en arguments par exemple. On peut également lui passer une valeur
“de départ” en deuxième argument qui sera ajoutée à la somme calculée.
La fonction max() retourne la plus grande valeur d’une donnée itérable, c’est-à-
dire d’une donnée dont on peut parcourir les différentes valeurs.
La fonction dir(), lorsqu’elle est utilisée sans argument, renvoie la liste des
variables et des fonctions (ou plus exactement des objets et des méthodes)
disponibles dans l’espace de portée courant. Nous étudierons ce que sont les
objets et méthodes par la suite.
Si on lui passe une donnée en argument, elle renverra la liste des méthodes
disponibles pour ce type de donnée.
80
PYTHON
81
PYTHON
Il est possible que vous ne compreniez pas tout d’un coup : pas d’inquiétude,
suivez le cours à votre rythme, avec moi, et les choses deviendront de plus en
plus claires au fil de votre avancement de le cours. N’hésitez pas à relire cette
partie en entier une fois que vous l’avez terminée pour revoir tous ces concepts
sous un oeil nouveau.
La programmation orientée objet repose sur le concept d’objets qui sont des
entités qui vont pouvoir posséder un ensemble de variables et de fonctions qui
leur sont propres.
Python est un langage résolument orienté objet, ce qui signifie que le langage
tout entier est construit autour de la notion d’objets.
En fait, quasiment tout en Python est avant tout un objet et nous avons manipulé
des objets depuis le début de ce cours sans nous en rendre compte : les types str,
int, list, etc. sont avant tout des objets, les fonctions sont des objets, etc.
Vous pouvez déjà noter que Python parle “d’attributs” pour désigner les
variables et fonctions d’un objet et plus précisément “d’attributs de données”
pour désigner les variables d’un objet et de “méthodes” pour désigner les
fonctions qui lui sont propres.
En POO, un objet ne peut pas être créé ex nihiliste (à partir de rien). La plupart
des langages qui supportent l’orienté objet (dont le Python) utilisent d’autres
entités pour créer des objets qu’on appelle des classes.
En fait, on peut aller jusqu’à considérer que les classes sont les principaux outils
de la POO puisqu’elles permettent de mettre en place des concepts
fondamentaux de la POO comme l’héritage, l’encapsulation ou le
polymorphisme qui sont des concepts qu’on expliquera et qu’on étudiera en
détail plus tard.
Pour créer des objets à partir d’une classe en Python, on va utiliser cette classe
comme une fonction. Pour illustrer concrètement comment cela fonctionne et
pour que vous compreniez plus facilement, créons immédiatement une première
classe qu’on va appeler Utilisateur.
Pour créer une nouvelle classe Python on utilise le mot clef class suivi du nom
de notre classe. Ici, on va créer une classe Utilisateur qui va être très simple pour
le moment.
Je vous accorde que ce code peut faire peut à priori car il contient de
nombreuses nouvelles choses. Pas d’inquiétude, nous allons l’expliquer au fur et
à mesure.
Ici, on crée une nouvelle classe Utilisateur avec la syntaxe class Utilisateur:.
Notez que par convention le nom d’une classe commence toujours par une
majuscule.
Cette classe Utilisateur possède ici deux variables statut et age et définit
également une fonction setNom(). Le rôle de la fonction setNom() va être de
permettre par la suite à nos objets de type Utilisateur() de définir un attribut de
donnée nom avec une valeur qui va être propre à chacun. Je vous demande de ne
pas vous préoccuper de l’argument self le moment.
84
PYTHON
Pour créer des objets à partir de cette classe, nous allons utiliser la syntaxe
Utilisateur() comme ceci :
Lorsqu’on crée un objet à partir d’une classe comme ceci, on dit également
qu’on instancie une classe (on crée une nouvelle instance d’une classe). Ici, on
instancie deux fois notre classe et on place le résultat dans deux variables pierre
et mathilde qui deviennent automatiquement des objets de type Utilisateur.
La chose que vous devez absolument comprendre ici est que les objets créés à
partir d’une classe en Python vont automatiquement avoir accès aux variables et
fonctions définies dans la classe qui vont être pour eux des attributs de données
et des méthodes.
Nos objets pierre et mathilde disposent donc ici tous les deux de deux attributs
de données statut et age qui possèdent les valeurs Inscrit et 0 et ont également
accès à la méthode setNom().
Pour accéder aux attributs de données et aux méthodes d’un objet, il va falloir
mentionner l’objet suivi de l’opérateur . (point) suivi du nom de l’attribut de
donnée ou de la méthode à laquelle on souhaite accéder comme ceci :
85
PYTHON
Ce n’est pas tout : nos objets vont également pouvoir définir des valeurs
personnalisées pour leurs attributs de données et on va également pouvoir
définir de nouveaux attributs de données qui vont être propres à un objet en
particulier dans une classe :
Si vous ne comprenez pas tout pour le moment et si vous êtes un peu perdu,
aucune inquiétude : c’est tout à fait normal. Considérez qu’entamer la POO est
un petit peu comme si vous commenciez ce cours.
Plus vous allez avancer dans cette partie, plus les différents éléments vont faire
sens et mieux vous comprendrez chaque chose car la plupart des concepts
présentés ici ont besoin que vous connaissiez d’autres concepts pour être
compris mais pour vous présenter ces autres concepts j’ai besoin de vous
présenter avant les premier concepts bref… C’est l’histoire du serpent qui se
mord la queue ou de l’oeuf et la poule : il faut choisir un angle d’attaque pour
expliquer la suite et progresser.
Pour le moment, je vous conseille de ne pas trop vous formaliser sur cette
nouvelle syntaxe ni sur les nouveaux termes. Essayez simplement de retenir ces
deux points pour la suite :
Les classes sont des ensembles de code qui contiennent des variables et
des fonctions et qui vont nous servir à créer des objets ;
Les objets créés à partir d’une classe disposent automatiquement des
variables et des fonctions définies dans la classe.
Les classes permettent de réunir des données et des fonctionnalités. Ici, vous
devez bien comprendre qu’une classe n’est finalement qu’un objet qui permet de
créer d’autres objets de même type. Comme cet objet est différent des autres, on
appelle cela une “classe” mais ce n’est que du vocabulaire.
Créer une nouvelle classe en Python revient à créer un nouveau type d’objet et
de fait un nouveau type de données. On va ensuite pouvoir instance notre classe
pour créer des objets qui vont partager les variables et fonctions de leur classe.
Pour désigner les variables et les fonctions que les objets héritent de leur classe,
Python utilise les termes “attributs de données” et “méthodes”.
87
PYTHON
Les termes employés sont différents (et le sont dans tous les langages qui
supportent l’orienté objet) car ils servent à désigner des éléments de langage
différents.
L’idée principale à retenir ici est qu’un attribut de donnée ou une méthode est
propre à un objet tandis qu’une variable ou une fonction est indépendante de
tout objet. C’est la raison pour laquelle pour accéder à un attribut de données ou
à une méthode on doit préciser le nom de l’objet qui souhaite y accéder avant.
En plus de cela, notez qu’un objet peut également définir ses propres attributs de
données ou surcharger des attributs de données de classe.
L’un des grands intérêts des classes est qu’elles permettent l’encapsulation du
code, c’est-à-dire le fait d’enfermer le code dans une “capsule”, dans un espace
en dehors de l’espace global. Cela permet d’éviter d’utiliser des variables
globales et de polluer l’espace global du script.
En effet, dans tous les langages de programmation, il est considéré comme une
bonne pratique de limiter le recours aux variables globales car cela rend le code
non flexible, non modulable, et dur à entretenir.
Pour comprendre cela, il faut penser au fait que la plupart des programmes
aujourd’hui contiennent des dizaines de fichiers qui contiennent chacun des
centaines de lignes de code et qui font appel à de nombreux modules externes,
c’est-à-dire à des code préconçus fournis par d’autres personnes.
Pour cette raison, un bon développeur fera tout pour compartimenter son code
en créant des espaces de portée ou “espaces de noms” bien définis et dont les
éléments ne pourront pas entrer en conflit avec les autres.
88
PYTHON
Les classes nous permettent de mettre en place cela puisque chaque objet créé à
partir d’une classe sa posséder SES attributs de données et SES méthodes qui ne
vont pas être accessibles depuis l’extérieur de l’objet et qui ne vont donc pas
polluer l’espace global.
Dans la leçon précédente, nous avons défini une première classe Utilisateur() et
avons créé deux objets pierre et mathilde à partir de cette classe comme cela :
Ici, lors de leur création, les deux objets pierre et mathilde disposent des mêmes
attributs avec les mêmes valeurs telles que définies dans la classe.
Pour réaliser cela, nous allons modifier notre classe et lui ajouter une fonction
spéciale appelée __init__() (deux underscores avant et deux après le nom) qui
permet “d’initialiser” ou de “construire” nos objets.
de l’instanciation, via Utilisateur() dans notre cas et ces arguments vont être
transmis à __init__().
Observons de plus près notre fonction __init__(). Comme vous pouvez le voir,
celle-ci accepte trois paramètres en entrée qu’on a ici nommé self, nom et age.
Il est maintenant temps de vous expliquer ce que signifie ce self qui était déjà
présent dans notre dernière définition de classe. Pour cela, il faut retourner à
notre définition des méthodes.
90
PYTHON
Si vous vous rappelez bien, je vous ai dit au début de cette partie que quasiment
tout en Python était avant tout un objet et qu’en particulier les fonctions étaient
des objets de “type” fonction. Les fonctions d’une classe ne font pas exception :
ce sont également avant tout des objets.
Ce que vous devez absolument comprendre ici est qu’une des particularités des
méthodes est que l’objet qui l’appelle est passé comme premier argument de la
fonction telle que définie dans la classe. Ainsi, lorsqu’on écrit pierre.getNom()
par exemple, l’objet pierre est passé de manière implicite à getNom().
Notez ici qu’en Python “self” ne signifie rien et qu’on pourrait tout aussi bien
utiliser un autre nom, à la différence de nombreux autres langages orienté objet
où self est un mot clef réservé.
Cette fonction va également recevoir l’objet qui est en train d’être créé en
premier argument. Cet objet va donc remplacer le “self”. Ici, notre fonction
__init__() sert à effectuer deux affectations : self.user_name = nom et
self.user_age = age.
De manière générale, il est considéré comme une bonne pratique de ne créer des
variables de classe que pour définir des variables qui devraient avoir des valeurs
constantes à travers les différents objet de la classe lors de leur création.
Dans l’exemple précédent, par exemple, on peut imaginer que notre classe
Utilisateur nous sert à créer un nouvel objet de type “Utilisateur” dès qu’une
personne s’enregistre sur notre site.
Retenez également qu’on évitera de créer des variables de classe avec des
données altérables comme des listes ou des dictionnaires sauf dans des cas très
précis. En effet, une variable de classe “appartient” à tous les objets de la classe
par défaut.
Cela est dû au fait qu’une variable de classe est en fait “partagée” par tous les
objets de la classe. On dit que chaque objet de la classe accède à la variable par
référence.
92
PYTHON
La syntaxe pour définir une sous-classe à partir d’une classe de base est la
suivante :
Ici, Utilisateur est notre classe de base et Client est notre sous-classe.
Ce principe d’héritage va nous permettre de créer des classes de base qui vont
définir des fonctionnalités communes à plusieurs classes puis des sous-classes
qui vont hériter de ces fonctionnalités et pouvoir également définir leurs propres
fonctionnalités.
Cela permet in-fine d’obtenir un code plus modulable, mieux organisé, plus clair
et plus concis qui sont des objectifs majeurs pour tout bon développeur.
On ne parlera de surcharge que pour les méthodes car dans le cas des variables
définir une variable avec le même nom dans la sous-classe correspond
finalement à créer une variable locale à la sous-classe en plus de celle “globale”
(celle disponible dans la classe de base) mais ces deux variables continuent
d’exister à part entière et à être différente tandis que lorsqu’on réécrit une
méthode la nouvelle méthode remplace véritablement l’ancienne pour les objets
de la sous-classe.
La réponse à cette question est très simple : Python va rechercher les variables et
méthodes dans un ordre précis.
Notez ici que Python nous fournit également deux fonctions pour nous permettre
de tester le type d’une instance et l’héritage d’une classe.
Ces deux fonctions sont très utiles pour tester rapidement les liens hiérarchiques
entre certaines classes et objets et peuvent aider à comprendre plus facilement
un script complexe qui nous aurait été passé.
Ici, j’utilise un nouveau mot clef pass qui me sert à créer une fonction vide. En
effet, le mot clef pass ne fait strictement rien en Python. On est obligés de
l’utiliser pour créer une fonction vide car si on n’écrit rien dans notre fonction
l’interpréteur Python va renvoyer une erreur.
Ces trois sous classes vont par défaut hériter des membres de leur classe mère
Animaux et notamment de la méthode seDeplacer(). Ici, chacune de nos sous
classes va implémenter cette méthode différemment, c’est-à-dire va la définir
différemment.
Pour terminer cette leçon sur l’héritage et le polymorphisme, il faut savoir que
Python gère également une forme d’héritage multiple.
Dans la pratique, l’héritage multiple est une chose très difficile à mettre en place
au niveau du langage puisqu’il faut prendre en charge les cas où plusieurs
classes mères définissent les mêmes variables et fonctions et définir une
procédure pour indiquer de quelle définition la sous-classe héritera.
En Python, dans la majorité des cas, l’héritage va se faire selon l’ordre des
classes mères indiquées et cela de manière récursive. Imaginons qu’une sous-
classe AGrave hérite de trois classes A, Accent et Abracadabra dans cet ordre et
que la classe A hérite elle même de la classe Alphabet tandis que Abracadabra
hérite de Mot
Nous terminerons cette leçon avec un petit rappel sur “pourquoi coder en orienté
objet” qui, je l’espère, vous permettra de commencer à avoir une vision
d’ensemble claire sur la programmation orientée objet et sur ses objectifs.
Dans la plupart des langages qui supportent l’orienté objet, on peut définir des
“niveaux de visibilité” ou “niveaux d’accès” pour les membres des classes
(c’est-à-dire pour les variables et les fonctions).
Attention ici : ce ne sont que des conventions qui n’ont aucun équivalent réel en
Python : on va pouvoir informer d’autres développeurs du niveau de visibilité
souhaité pour un membre mais tous les membres seront toujours publics en
Python et il est de la responsabilité des autres développeurs de suivre nos
indications ou pas.
Il est à noter que ces conventions n’ont pas été adoptées par hasard. En effet,
Python possède un mécanisme appelé “name mangling” qui fait que tout
membre de classe commençant par deux underscores, c’est-à-dire de la forme
__nom-du-membre sera remplacé textuellement lors de l’interprétation par
_nom-de-classe__nom-du-membre.
Cela fait que si un développeur essaie d’utiliser un membre défini avec deux
underscores tel quel, Python renverra une erreur puisqu’il préfixera le nom avec
un underscore et le nom de la classe du membre.
Cette règle a été prévue par Python pour éviter les accidents de conflits entre
plusieurs membres de plusieurs classes qui auraient le même nom. Elle
n’empêche pas d’accéder ou de modifier un membre “privé”. En effet, il suffit
de préfixer le membre de la même façon que Python lors de son interprétation
pour y accéder.
On définit ici une classe Visibilite qui contient trois variables public, _protected
et __private. Notez qu’on pourrait aussi bien définir des fonctions de la même
manière.
Comme vous le voyez, on accède sans souci à nos variables public et _protected.
En revanche, pour __private, le mécanisme de name mangling s’active et le nom
passé est préfixé par un underscore et le nom de la classe. On peut cependant
contourner cela et toujours afficher le contenu de la variable privée en utilisant
la notation _Visibiilite__private.
Il est possible que vous ne voyez pas l’intérêt de tout cela si vous n’avez pas
beaucoup d’expérience en programmation. Dans ce cas, il est important de
retenir et de vous persuader qu’une immense partie du travail d’un développeur
est de s’assurer d’avoir un code le plus clair, concis et modulable possible (en
plus d’être fonctionnel bien évidemment). Toutes ces notions liées à l’orienté
objet permettent de servir ces objectifs.
“Itérer” signifie en français classique “répéter, faire une seconde fois”. Dans le
contexte de la programmation orienté objet, “itérer” sur un objet signifie
parcourir l’objet attribut par attribut pour accéder à leur valeur.
Les itérateurs sont implicitement utilisés chaque fois que nous manipulons des
collections de données comme les list, tuple ou string (qui sont des objets dits
“itérables”).
La méthode habituelle pour parcourir une collection est d’utiliser une boucle for.
Lorsque nous utilisons une boucle for pour parcourir un objet itérable, la boucle
appelle en fait en interne la fonction iter() sur l’objet itérable.
Au lieu d’utiliser la boucle for comme indiqué ci-dessus, nous pouvons utiliser
la fonction itérateur iter(). Un itérateur est un objet qui représente un flux de
données. Il retourne un élément à la fois.
Chaque fois que __next__() est appelée, l’élément suivant du flux itérateur est
renvoyé. Lorsqu’il n’y a plus d’éléments disponibles, __next__() lève une erreur
StopIteration.
On va pouvoir définir nos propres itérateurs dans nos classes pour itérer de
manière particulière sur nos objets itérables (en partant de la fin, en sautant des
caractères, etc.).
Pour cela, il suffit de définir une méthode __iter__() qui renvoie un objet
disposant d’une méthode __next__(). Si la classe définit elle-même la méthode
__next__(), alors __iter__() peut simplement renvoyer self.
105
PYTHON
Ici, on crée une classe qui définit un itérateur qui va sauter une donnée de la
séquence sur laquelle il Isère à chaque nouveau passage.
La syntaxe d’un générateur est la même que celle d’une fonction classique à la
différence que les générateurs utilisent l’instruction yield à la place de return
pour retourner des données.
Ces fonctionnalités font des générateurs des outils privilégiés pour créer des
itérateurs de manière plus simple.
Lorsqu’on crée une liste, un dictionnaire, une chaine de caractères, etc. on crée
avant tout un nouvel objet à partir des classes list, dict, str, etc.
107
PYTHON
La plupart de ces classes définissent des méthodes qui permettent de réaliser des
opérations courantes sur chaque type de donnée. Dans cette leçon, nous allons
passer en revue quelques unes des méthodes qui pourront certainement vous être
utiles par la suite et qu’il faut connaitre pour les types de données str, list, et
dict.
Pour obtenir la liste complète d’un méthode qu’on peut utiliser avec un type de
données, il suffit d’appeler la fonction dir() en lui passant un objet en argument.
108
PYTHON
Parmi les méthodes qu’on va le plus utiliser, on peut mentionner les méthodes
lower(), upper() et capitalize() qui renvoient respectivement une chaine de
caractères en minuscules, majuscules, et avec la première lettre en majuscule.
Attention : la chaîne à laquelle on applique cette méthode est celle qui servira de
séparateur (un ou plusieurs caractères) ; l’argument transmis est la liste des
chaînes à rassembler. Si on lui passe un dictionnaire en argument, les valeurs
retournées seront les clefs du dictionnaire.
111
PYTHON
La méthode format() est une des méthodes qu’il faut absolument connaitre en
Python. Elle permet de formater des chaines de caractères. On va utiliser des
accolades pour définir des parties de chaines qui devront être formatées.
Nous allons également pouvoir utiliser les méthodes suivantes avec les listes :
append(), clear(), copy(), count(), extend(), index(), insert(), pop(), remove(),
reverse(), sort.
La méthode pop() retire et renvoie l’élément de la liste dont l’index est passé en
argument. Si on ne lui passe pas d’argument, le dernier élément sera supprimé.
La méthode sort() permet de classer les éléments d’une liste dans l’ordre
alphabétique. On peut lui passer un argument reverse = True pour que la liste
soit classée dans l’ordre alphabétique inversé (de Z à A).
113
PYTHON
Nous allons également pouvoir utiliser les méthodes suivantes avec ce type de
données : clear(), copy(), fromkeys(), get(), items(), keys(), pop(), popitem(),
setdefault(), update(), values.
La méthode Python keys() renvoie la liste des clefs utilisées dans un dictionnaire
tandis que la méthode values() renvoie la liste des valeurs d’un dictionnaire. La
méthode get() renvoie elle la valeur de l’élément du dictionnaire possédant la
clef spécifiée.
Les modules standards qui ne font pas partie du langage en soi mais sont
intégrés automatiquement par Python ;
Les modules développés par des développeurs externes qu’on va pouvoir
utiliser ;
Les modules qu’on va développer nous mêmes.
Dans tous les cas, la procédure à suivre pour utiliser un mode sera la même.
Nous allons commencer par décrire cette procédure puis nous étudierons dans la
suite de cette partie quelques modules standards qu’il convient de connaitre.
Ensuite, enregistrez le dans le dossier Python que vous devriez avoir créé au
début de ce cours et qui devrait se trouver sur votre bureau.
Dès que tout cela est fait, on peut retourner dans le terminal ou l’invite de
commande. Ne lancez pas l’interpréteur pour le moment et pensez bien à définir
le dossier Python comme dossier de référence pour la recherche de fichiers
Python si ça n’a pas été fait au début de ce cours.
Pour cela, vous pouvez utiliser la commande cd (pour “change directory”) suivie
du chemin du dossier qui doit être le dossier de référence (Desktop/Python pour
Mac par exemple).
On peut ensuite lancer l’interpréteur Python. Ici, il faut imaginer que notre
terminal / invite de commande représente le script principal de notre
programme. On va importer notre module dans ce script principal grâce à
l’instruction import bonjour.
1. Le répertoire courant ;
2. Si le module est introuvable, Python recherche ensuite chaque répertoire
listé dans la variable shell PYTHONPATH ;
3. Si tout échoue, Python vérifie le chemin par défaut. Sous UNIX, ce
chemin par défaut est normalement /usr/local/lib/python/.
Dès que notre module est importé, on va pouvoir accéder tout simplement aux
variables et fonctions de notre module depuis notre script en préfixant le nom
des éléments du module par le nom du module et un point comme ceci :
On peut utiliser le mot clef as pour renommer un module ou plutôt pour créer un
alias de nom. Cela peut permettre d’obtenir des scripts plus courts et plus clairs
dans le cas où le nom du module est inutilement long ou s’il est peu descriptif.
Note : on ne peut importer un module qu’une fois dans un script. Si vous testez
le code ci-dessus et si vous aviez déjà importé le module précédemment, il
faudra que vous quittiez l’interpréteur et que vous le relanciez pour que tout
fonctionne. Pour quitter l’interpréteur, vous pouvez utiliser l’instruction quit().
119
PYTHON
Parfois, nous n’aurons besoin que de certains éléments précis dans un module.
On va alors pouvoir se contenter d’importer ces éléments en particulier. Pou
cela, on va utiliser l’instruction from nom-du-module import un-element.
Pour faire cela, on peut utiliser la fonction dir() qui renvoie la liste de toutes les
fonctions et variables d’un module.
120
PYTHON
Comme vous pouvez le voir, tout fichier Python possède par défaut des éléments
de configuration.
Comme je vous l’ai dit au début de cette leçon, nous importerons bien souvent
des modules créés par d’autres développeurs ou des modules mis à notre
disposition par Python lui même.
Pour importer un module Python, nous allons à nouveau tout simplement utiliser
une instruction import comme si on importait l’un de nos modules.
Vous pouvez retrouver la liste complète des modules standards Python sur le site
officiel.
Attention : les fonctions de ce module ne peuvent pas être utilisées avec des
nombres complexes. Pour cela, il faudra plutôt utiliser les fonctions du module
cmath.
Le module random nous fournit des outils pour générer des nombres pseudo-
aléatoires de différentes façons.
Le module random est très riche et contient de nombreuses fonctions qui vont
nous permettre de générer des nombres pseudo aléatoires de différentes
manières et pour différentes situations. Je vous invite à les découvrir en détail
dans la documentation.
Le module statistics nous fournit des outils nous permettant d’effectuer des
calculs de statistiques peu complexes, comme des calculs de moyenne, de
médiane ou de variance.
Ce module fournit des fonctions pour le calcul de valeurs statistiques sur des
données numériques (valeurs réelles de la classe Real).
Ce module n'est pas pensé comme substitut à des bibliothèques tierces telles que
NumPy, SciPy ou des suites logicielles propriétaires complètes à destination des
statisticiens professionnels comme Minitab, SAS ou Matlab. Ce module se situe
au niveau des calculatrices scientifiques graphiques.
À moins que cela ne soit précisé différemment, ces fonctions gèrent les objets
int, float, Decimal et Fraction. Leur bon comportement avec d'autres types
(numériques ou non) n'est pas garanti. Le comportement de ces fonctions sur des
collections mixtes de différents types est indéfini et dépend de l'implémentation.
Si vos données comportement un mélange de plusieurs types, vous pouvez
utiliser map() pour vous assurer que le résultat est cohérent, par exemple :
map(float, input_data).
Ces fonctions calculent une moyenne ou une valeur typique à partir d'une
population ou d'un échantillon.
125
PYTHON
Mesures de la dispersion
Écart-type de la
pstdev()
population.
pvariance(
Variance de la population.
)
Écart-type d'un
stdev()
échantillon.
variance() Variance d'un échantillon.
Note : les fonctions ne requièrent pas que les données soient ordonnées.
Toutefois, pour en faciliter la lecture, les exemples utiliseront des séquences
croissantes.
statistics.mean(data)
Exemples d'utilisation :
Note
statistics.fmean(data)
Cette fonction est plus rapide que mean() et renvoie toujours un float.
data peut être une séquence ou un itérable. Si les données d'entrée sont
vides, la fonction lève une erreur StatisticsError.
statistics.geometric_mean(data)
Aucune mesure particulière n'est prise pour garantir que le résultat est
parfaitement exact (cela peut toutefois changer dans une version future).
statistics.harmonic_mean(data)
Une erreur StatisticsError est levée si data est vide ou si l'un de ses
éléments est inférieur à zéro.
statistics.median(data)
Cette approche est adaptée à des données discrètes à condition que vous
acceptiez que la médiane ne fasse pas nécessairement partie des
observations.
Si les données sont ordinales (elles peuvent être ordonnées) mais pas
numériques (elles ne peuvent être additionnées), utilisez median_low() ou
median_high() à la place.
statistics.median_low(data)
La médiane basse est toujours une valeur représentée dans les données.
Lorsque le nombre d'observations est impair, la valeur du milieu est
renvoyée. Sinon, la plus petite des deux valeurs du milieu est renvoyée.
Utilisez la médiane basse lorsque vos données sont discrètes et que vous
préférez que la médiane soit une valeur représentée dans vos observations
plutôt que le résultat d'une interpolation.
statistics.median_high(data)
La médiane haute est toujours une valeur représentée dans les données.
Lorsque le nombre d'observations est impair, la valeur du milieu est
renvoyée. Sinon, la plus grande des deux valeurs du milieu est renvoyée.
Utilisez la médiane haute lorsque vos données sont discrètes et que vous
préférez que la médiane soit une valeur représentée dans vos observations
plutôt que le résultat d'une interpolation.
130
PYTHON
statistics.median_grouped(data, interval=1)
Dans l'exemple ci-dessous, les valeurs sont arrondies de sorte que chaque
valeur représente le milieu d'un groupe. Par exemple 1 est le milieu du
groupe 0,5 - 1, 2 est le milieu du groupe 1,5 - 2,5, 3 est le milieu de 2,5
- 3,5, etc. Compte-tenu des valeurs ci-dessous, la valeur centrale se situe
quelque part dans le groupe 3,5 - 4,5 et est estimée par interpolation :
Cette fonction ne vérifie pas que les valeurs sont bien séparées d'au moins
une fois interval.
Voir aussi
statistics.mode(data)
131
PYTHON
S'il existe plusieurs modes avec la même fréquence, cette fonction renvoie
le premier qui a été rencontré dans data. Utilisez min(multimode(data))
ou max(multimode(data)) si vous désirez le plus petit mode ou le plus
grand mode. Lève une erreur StatisticsError si data est vide.
mode suppose que les données sont discrètes et renvoie une seule valeur.
Il s'agit de la définition usuelle du mode telle qu'enseignée dans à l'école :
Modifié dans la version 3.8: Gère désormais des jeux de données avec
plusieurs modes en renvoyant le premier mode rencontré. Précédemment,
une erreur StatisticsError était levée si plusieurs modes étaient trouvés.
statistics.multimode(data)
Renvoie une liste des valeurs les plus fréquentes en suivant leur ordre
d'apparition dans data. Renvoie plusieurs résultats s'il y a plusieurs modes
ou une liste vide si data est vide :
>>> multimode('aabbbbccddddeeffffgg')
['b', 'd', 'f']
>>> multimode('')
[]
statistics.pstdev(data, mu=None)
0.986893273527251
statistics.pvariance(data, mu=None)
Si le second argument optionnel mu est n'est pas spécifié ou est None (par
défaut), il est remplacé automatiquement par la moyenne arithmétique.
Cet argument correspond en général à la moyenne de data. En le
spécifiant autrement, cela permet de calculer le moment de second ordre
autour d'un point qui n'est pas la moyenne.
Exemples :
>>> data = [0.0, 0.25, 0.25, 1.25, 1.5, 1.75, 2.75, 3.25]
>>> pvariance(data)
1.25
>>> mu = mean(data)
>>> pvariance(data, mu)
1.25
Fraction(13, 72)
Note
statistics.stdev(data, xbar=None)
Exemples :
>>> variance(data)
1.3720238095238095
>>> m = mean(data)
>>> variance(data, m)
1.3720238095238095
Cette fonction ne vérifie pas que la valeur passée dans l'argument xbar
correspond bien à la moyenne. Utiliser des valeurs arbitraires pour xbar
produit des résultats impossibles ou incorrects.
Note
Utilisez n = 4 pour obtenir les quartiles (le défaut), n = 10 pour obtenir les
déciles et n = 100 pour obtenir les centiles (ce qui produit 99 valeurs qui
séparent data en 100 groupes de même taille). Lève une erreur
StatisticsError si n est strictement inférieur à 1.
Les quantiles sont linéairement interpolées à partir des deux valeurs les
plus proches dans l'échantillon. Par exemple, si un quantile se situe à un
tiers de la distance entre les deux valeurs de l'échantillon 100 et 112, le
quantile vaudra 104.
La valeur par défaut pour method est "exclusive" et est applicable pour
des données échantillonnées dans une population dont une des valeurs
extrêmes peut être plus grande (respectivement plus petite) que le
maximum (respectivement le minimum) des valeurs de l'échantillon. La
proportion de la population se situant en-dessous du i e de m valeurs
ordonnées est calculée par la formule i / (m + 1). Par exemple, en
supposant 9 valeurs dans l'échantillon, cette méthode les ordonne et leur
associe les quantiles suivants : 10%, 20%, 30%, 40%, 50%, 60%,
70%, 80%, 90%.
Exceptions
exception statistics.StatisticsError
Objets NormalDist
mean
median
mode
stdev
137
PYTHON
variance
classmethod from_samples(data)
data peut être n'importe quel iterable de valeurs pouvant être converties
en float. Lève une erreur StatisticsError si data ne contient pas au moins
deux éléments car il faut au moins un point pour estimer la moyenne et
deux points pour estimer la variance.
samples(n, *, seed=None)
Si seed est spécifié, sa valeur est utilisée pour initialiser une nouvelle
instance du générateur de nombres aléatoires. Cela permet de produire des
résultats reproductibles même dans un contexte de parallélisme par fils
d'exécution.
pdf(x)
cdf(x)
inv_cdf(p)
overlap(other)
quantiles(n=4)
Utilisez n = 4 pour obtenir les quartiles (le défaut), n = 10 pour obtenir les
déciles et n = 100 pour obtenir les centiles (ce qui produit 99 valeurs qui
séparent data en 100 groupes de même taille).
Diviser une constante par une instance de NormalDist n'est pas pris en
charge car le résultat ne serait pas une loi normale.
Étant donné que les lois normales sont issues des propriétés additives de
variables indépendantes, il est possible d'ajouter ou de soustraite deux
variables normales indépendantes représentées par des instances de
NormalDist. Par exemple :
3.1
>>> round(combined.stdev, 1)
0.5
Par exemple, sachant que les scores aux examens SAT suivent une loi normale
de moyenne 1060 et d'écart-type 195, déterminer le pourcentage d'étudiants dont
les scores se situent entre 1100 et 1200, arrondi à l'entier le plus proche :
Les lois normales peuvent être utilisées pour approcher des lois binomiales
lorsque le nombre d'observations est grand et que la probabilité de succès de
l'épreuve est proche de 50%.
140
PYTHON
Par exemple, 750 personnes assistent à une conférence sur le logiciel libre. Il y a
deux salles pouvant chacune accueillir 500 personnes. Dans la première salle a
lieu une présentation sur Python, dans l'autre une présentation à propos de Ruby.
Lors des conférences passées, 65% des personnes ont préféré écouter les
présentations sur Python. En supposant que les préférences de la population
n'ont pas changé, quelle est la probabilité que la salle Python reste en-dessous de
sa capacité d'accueil ?
La prédiction finale est celle qui a la plus grande probabilité a posteriori. Cette
approche est appelée maximum a posteriori ou MAP :
Python distingue deux sorte d’objets date et time : les objets “avisés” et les
objets “naifs”. Un objet avisé est un objet qui possède suffisamment de
connaissances internes pour se situer de façon relative par rapport à d’autres
142
PYTHON
objets avisés. Un objet naïf ne comporte pas assez d’informations pour se situer
sans ambiguïté par rapport à d’autres objets date ou time.
Ici, vous pouvez tenir que les objets avisés datetime et time ont un attribut
optionnel d’information sur le fuseau horaire nommé tzinfo. Cet attribut ou objet
tzinfo capture l’information à propos du décalage avec le temps UTC, le nom du
fuseau horaire, et si l’heure d’été est effective.
date : représente une date; possède des attributs year, month et day ;
time : représente un temps; possède des attributs hour, minute, second,
microsecond et tzinfo ;
datetime : combinaison d’une date et d’un temps; possède des attributs
year, month, day, hour, minute, second, microsecond et tzinfo;
timedelta : représente la différence entre deux objets date, time ou
datetime exprimée en microsecondes ;
tzinfo : classe de base abstraite (= qui ne peut pas directement être
instanciée) pour les objets portants des informations sur les fuseaux
horaires ;
timezone : classe qui implémente la classe abstraite <code<tzinfo<
code="">.</code<tzinfo<>
Pour une référence complète sur le module Python datetime, je vous invite à
consulter la documentation.
Le module Python time fournit différentes fonctions liées au temps. Il peut et est
généralement utilisé conjointement avec le module datetime. Attention ici à ne
pas confondre le module time et la classe time du module datetime.
144
PYTHON
Inde Nom de
Ex de valeur
x l’attribut
0 tm_year 2000, 2010, 2019
1 tm_mon plage [1, 12]
2 tm_mday plage [1, 31]
3 tm_hour plage [0,23]
4 tm_min plage [0,59]
5 tm_sec plage [0,61]
6 tm_wday plage [0, 6], Lundi valant 0
7 tm_yday plage [1, 366]
8 tm_isdst 0, 1 ou -1
abréviation du nom du fuseau
– tm_zone
horaire
décalage à l’est de UTC en
– tm_gmtoff
secondes
145
PYTHON
Directiv
Signification
e
%a Nom abrégé du jour de la semaine selon les paramètres régionaux.
%A Le nom de semaine complet de la région.
%b Nom abrégé du mois de la région.
%B Nom complet du mois de la région.
Représentation appropriée de la date et de l’heure selon les paramètres
%c
régionaux.
%d Jour du mois sous forme décimale [01,31].
%H Heure (horloge sur 24 heures) sous forme de nombre décimal [00,23].
%I Heure (horloge sur 12 heures) sous forme de nombre décimal [01,12].
%j Jour de l’année sous forme de nombre décimal [001,366].
%m Mois sous forme décimale [01,12].
%M Minutes sous forme décimale [00,59].
%p L’équivalent local de AM ou PM.
%S Deuxième sous forme de nombre décimal [00,61].
Numéro de semaine de l’année (dimanche en tant que premier jour de la
semaine) sous forme décimale [00,53]. Tous les jours d’une nouvelle
%U
année précédant le premier dimanche sont considérés comme
appartenant à la semaine 0.
%w Jour de la semaine sous forme de nombre décimal [0 (dimanche), 6].
%W Numéro de semaine de l’année (lundi comme premier jour de la
146
PYTHON
Directiv
Signification
e
semaine) sous forme décimale [00,53]. Tous les jours d’une nouvelle
année précédant le premier lundi sont considérés comme appartenant à
la semaine 0.
%x Représentation de la date appropriée par les paramètres régionaux.
%X Représentation locale de l’heure.
%y Année sans siècle comme un nombre décimal [00, 99].
%Y Année complète sur quatre chiffres.
Décalage de fuseau horaire indiquant une différence de temps positive
ou négative par rapport à UTC / GMT de la forme +HHMM ou -
%z
HHMM, où H représente les chiffres des heures décimales et M, les
chiffres des minutes décimales [-23:59, +23:59].
Nom du fuseau horaire (pas de caractères s’il n’y a pas de fuseau
%Z
horaire).
%% Un caractère '%' littéral.
Ce module définit une classe Calendar qui va permettre de créer des objets de
type calendrier et une classe TextCalendar qui peut être utilisée pour générer des
calendriers en texte brut.
Les calendriers sont des objets très spécifiques qu’on ne manipule pas tous les
jours et je n’irai donc pas plus loin dans la présentation de ce module. Si vous
avez besoin un jour de créer un calendrier, sachez simplement que ce module
existe. Vous pourrez trouver toutes les informations relatives aux calendriers
Python sur la documentation officielle du module.
Les expressions régulières sont des schémas ou des motifs utilisés pour effectuer
des recherches et des remplacements dans des chaines de caractères.
Ces schémas ou motifs sont tout simplement des séquences de caractères dont
certains vont disposer de significations spéciales et qui vont nous servir de
schéma de recherche. On les appelle également des masques de recherche.
Le premier caractère à connaitre est l’antislash \ qui est utilisé par les
expressions rationnelles pour donner un sens spécial à certains caractères
normaux ou au contraire pour neutraliser (“échapper”) le sens d’un caractère
spécial et nous permettre de rechercher le caractère en soi sans qu’il exprime son
sens spécial.
Ici, nous sommes déjà confrontés à un souci puisque Python utilise également
l’antislash comme caractère d’échappement. Pour rechercher un antislash littéral
avec une expression régulière il faudrait donc écrire \\\\ puisque chaque antislash
doit être représenté par \\ dans une chaine littérale Python et que pour rechercher
un antislash (qui est un caractère spécial) dans une expression rationnelle il faut
écrire \\ (le premier antislash servant de caractère d’échappement pour
rechercher le deuxième).
Ensuite, vous devez savoir que certains caractères ne vont avoir un sens spécial
qu’en dehors de ce qu’on appelle des classes de caractères ou vont pouvoir avoir
des sens spéciaux différents selon qu’ils soient dans des classes de caractères ou
en dehors. Commençons déjà par comprendre ce qu’est une classe de
caractères.
Pour déclarer une classe de caractères dans notre masque de recherche, nous
allons utiliser une paire de crochets [ ] qui vont nous permettre de délimiter la
classe en question.
Au sein des classes de caractères, seuls les caractères suivants possèdent une
signification spéciale :
Métacaractè
Description
re
Notez qu’il faudra également protéger les caractères de classe (les crochets) si
on souhaite les inclure pour les rechercher dans une classe de caractères car dans
150
PYTHON
La syntaxe des classes abrégées utilise l’antislash suivi d’un caractère “normal”
afin de lui donner dans un cas une signification spéciale. Les classes abrégées
les plus intéressantes sont les suivantes (faites bien attention aux emplois de
majuscules et de minuscules ici !) :
Métacaractè
Représente
re
* 0, 1 ou plusieurs occurrences
+ 1 ou plusieurs occurrences
? 0 ou 1 occurrence
Maintenant que nous avons (très rapidement) parcouru les éléments de syntaxe
principaux des expressions régulières, il est temps de les utiliser avec le module
re de manière pratique.
Une expression rationnelle en soi n’est qu’un motif. Nous allons donc utiliser
des fonctions qui vont permettre d’effectuer des recherches de motifs dans des
chaines, des remplacements, etc.
Jusqu’à présent, nous avons utilisé des variables pour stocker des données sous
forme de chaines, de listes, de dictionnaires, etc.
Les variables sont très pratiques car elles vont nous permettre de manipuler nos
données très facilement en Python. Cependant, elles ne vont pas toujours être les
outils les mieux adaptés pour stocker des données.
En effet, le gros “défaut” des variables est qu’elles ne peuvent stocker une
information que temporairement (au mieux le temps de l’exécution d’un script).
Nous utiliserons donc les fichiers pour des programmes aux ambitions plus
modestes et lorsqu’on n’aura pas de trop grosses quantités d’informations à
stocker et au contraire les bases de données lorsque le besoin d’une structure
plus robuste se fera sentir.
Nous allons pouvoir effectuer toutes sortes de manipulations sur nos fichiers en
Python : création d’un fichier, lecture des données, écriture, etc. Pour réaliser
ces opérations, il va cependant avant tout falloir ouvrir le fichier. Pour cela, on
utilise la fonction fopen().
Mode
Description
d’ouverture
Mode
Description
d’ouverture
Notez qu’on va également pouvoir rajouter une autre lettre derrière le mode pour
définir si le fichier doit être ouvert en mode texte (lettre t, valeur par défaut ou
en mode binaire (lettre b). Dans ce cours, nous nous concentrerons sur le mode
texte et n’aborderons pas le mode binaire, généralement moins utilisé.
Une fois qu’on a terminé de manipuler un fichier, il est considéré comme une
bonne pratique de le fumer. Cela évite d’utiliser des ressources inutilement et
d’obtenir certains comportements inattendus.
Pour fermer un fichier, on peut soit utiliser la méthode close() soit idéalement
ajouter le mot clef with avant open() lors de l’ouverture du fichier qui garantira
que le fichier sera fermé automatiquement une fois les opérations terminées.
Avant d’aller plus loin dans la manipulation de fichier, il faut que je vous parle
de la position du curseur (ou « pointeur de fichier ») car celle-ci va impacter le
résultat de la plupart des manipulations qu’on va pouvoir effectuer sur les
fichiers. Il est donc essentiel de toujours savoir où se situe ce pointeur et
également de savoir comment le bouger.
Le curseur ou pointeur est l’endroit dans un fichier à partir duquel une opération
va être faite. Pour donner un exemple concret, le curseur dans un document
Word, dans un champ de formulaire ou lorsque vous effectuez une recherche
Google ou tapez une URL dans votre navigateur correspond à la barre
clignotante.
Ce curseur indique l’emplacement à partir duquel vous allez écrire votre requête
ou supprimer un caractère, etc. Le curseur dans les fichiers va être exactement la
même chose à la différence qu’ici on ne peut pas le voir visuellement.
157
PYTHON
Pour insérer des données dans un fichier, c’est-à-dire pour écrire dans un fichier,
on utilisera la méthode write(). On va passer les données à insérer en argument
de write().
Cette méthode n’accepte que des données de type chaines de caractères : pensez
donc bien à convertir vos données au bon format avant tout.
De plus, notez bien que les données seront écrites à partir de la position du
curseur interne et que si celui-ci est situé au début ou au milieu du fichier les
nouvelles données écraseront les anciennes.
158
PYTHON
Pour ne lire qu’une partie d’un fichier, on peut passer un nombre en argument à
read() qui lui indiquera combien de caractères lire à partir de la position
courante du pointeur interne.
Enfin, pour ne lire qu’une ligne d’un fichier, on peut utiliser la méthode
readline().
Ici, on teste si le fichier a bien été supprimé en observant si exists() renvoie bien
False ou pas (note l’utilisation de l’opérateur logique inverse not en début de
condition if).
162
PYTHON
JSON peut représenter des nombres, des booléens, des chaînes, la valeur null,
des séquences de valeurs ordonnées, des objets, etc. JSON ne représente pas
nativement des types de données plus complexes tels que des fonctions, des
expressions régulières, des dates, etc.
JSON est un format d’échange de données pensé pour gérer deux structures de
données universelles :
Une valeur peut être une chaine de caractères entourées par des guillemets
doubles, un nombre, un booléen, la valeur null, un objet ou un tableau.
Pour formater des données Python en JSON et inversement, nous allons utiliser
le module Python standard json.
Pour sérialiser des données, c’est-dire pour convertir un objet Python en chaine
JSON, nous allons pouvoir utiliser l’une des méthodes dump() ou dumps() du
module json.
164
PYTHON
Les objets Python vont être convertis selon la table d’équivalence suivante :
Python JSON
dict object
str string
True true
False false
None null
Ici, on définit un dictionnaire Python pierre qui contient des données de types
différents.
On ouvre ensuite un fichier “pierre.json” en écriture avec open() puis on écrit les
données sérialisées à l’intérieur grâce à dump(). On passe deux arguments à
dump() : les données à sérialisme et l’objet de type file (fichier) dans lequel elle
doivent être écrites.
En réalité, vous devez savoir que les méthodes dump() et dumps() acceptent de
nombreux arguments qui vont nous permettre de personnaliser le comportement
et notamment d’arranger nos données comme des arguments de type
“indentation”, “séparateur” ou “classement des clefs” pour indenter les données,
choisir nos séparateurs entre les valeurs ou classer les données par clefs.
166
PYTHON
De la même façon, nous allons pouvoir utiliser l’une des méthodes load() et
loads() pour désérialiser des données JSON, c’st-à-dire pour convertir des
données JSON en objet Python.
7.2 Gérer les exceptions en Python avec try, except, else et finally
Dans cette partie, nous allons apprendre à intercepter les erreurs renvoyées par
Python et à les gérer.
Par exemple, se servir d’une variable non déclarée dans un script, utiliser des
opérateurs avec des types de données qui ne les supportent pas ou oublier un
guillemet ou un deux points sont des erreurs de syntaxe faites par le
développeur.
Comme les erreurs de syntaxe sont des erreurs que nous avons faites, nous
pouvons les corriger directement et c’est ce qu’on s’efforcera à faire et
modifiant nos scripts. Pour les autres erreurs, en revanche, il va falloir mettre en
place un système de gestion d’erreurs qui indiquera au Python quoi faire si telle
ou telle erreur est rencontrée.
En Python, nous allons pouvoir intercepter certaines erreurs pour les prendre en
charge nous mêmes et pour décider si le script doit continuer de s’exécuter ou
pas.
En Python, les erreurs détectées durant l’exécution d’un script sont appelées des
exceptions car elles correspondent à un état “exceptionnel” du script.
Ici, nous avons trois types d’exceptions différentes : une exception NameError,
une exception ZeroDivisionError et une exception TypeError. Comment fait
Python pour analyser les types d’erreurs et renvoyer des messages différents en
fonction ?
classe. Ensuite, nous avons également quatre autres classes d’exception de base
(qui dérivent de BaseException) :
Les exceptions natives présentes ci-dessous peuvent être levées par l'interpréteur
ou par les fonctions natives. Sauf mention contraire, une "valeur associée"
indique la cause de l'erreur. Cela peut être une chaîne ou un tuple contenant
plusieurs éléments d'information (e.g., un code d'erreur ou un message
explicatif). Cette valeur associée est généralement donnée en argument du
constructeur de la classe.
Du code utilisateur peut lever des exceptions natives. Cela peut être utilisé pour
tester un gestionnaire d'exception ou pour rapporter une condition d'erreur
171
PYTHON
"comme si" c'était l'interpréteur qui levait cette exception ; mais attention car
rien n'empêche du code utilisateur de lever une erreur inappropriée.
Les classes d'exception natives peuvent être héritées pour définir de nouvelles
exceptions ; les programmeurs sont encouragés à faire dériver les nouvelles
exceptions de la classe Exception ou d'une de ses sous-classes, et non de
BaseException. Plus d'informations sur la définition des exceptions sont
disponibles dans le Tutoriel Python au chapitre Exceptions définies par
l'utilisateur.
En levant (ou levant à nouveau) une exception dans une clause except ou finally,
__context__ est automatiquement assigné à la dernière exception interceptée ; si
la nouvelle exception n'est pas gérée, la trace d'appels affichée inclut la ou les
exception(s) d'origine et l'exception finale.
En levant une nouvelle exception (plutôt que d'utiliser un simple raise pour lever
à nouveau l'exception en cours de traitement), le contexte implicite d'exception
peut être complété par une cause explicite en utilisant from avec raise :
L'expression suivant from doit être une exception ou None. Elle sera assignée en
tant que __cause__ dans l'exception levée. Changer __cause__ change aussi
implicitement l'attribut __suppress_context__ à True, de sorte que l'utilisation de
raise new_exc from None remplace bien l'ancienne exception avec la nouvelle à
des fins d'affichage (e.g., convertir KeyError en AttributeError), tout en laissant
l'ancienne exception disponible dans __context__ pour introspection lors du
débogage.
Dans les deux cas, l'exception elle-même est toujours affichée après toutes les
exceptions enchaînées, de sorte que la dernière ligne de la trace d'appels montre
toujours la dernière exception qui a été levée.
exception BaseException
La classe de base pour toutes les exceptions natives. Elle n'est pas vouée à
être héritée directement par des classes utilisateur (pour cela, utilisez
Exception). Si str() est appelée sur une instance de cette classe, la
représentation du ou des argument(s) de l'instance est retournée, ou la
chaîne vide s'il n'y avait pas d'arguments.
args
with_traceback(tb)
try:
...
except SomeException:
tb = sys.exc_info()[2]
raise OtherException(...).with_traceback(tb)
exception Exception
Toutes les exceptions natives, qui n'entraînent pas une sortie du système
dérivent de cette classe. Toutes les exceptions définies par l'utilisateur
devraient également être dérivées de cette classe.
exception ArithmeticError
La classe de base pour les exceptions natives qui sont levées pour diverses
erreurs arithmétiques : OverflowError, ZeroDivisionError,
FloatingPointError.
exception BufferError
exception LookupError
173
PYTHON
La classe de base pour les exceptions qui sont levées lorsqu'une clé ou un
index utilisé sur un tableau de correspondances ou une séquence est
invalide : IndexError, KeyError. Peut être levée directement par
codecs.lookup().
exception AssertionError
exception AttributeError
exception EOFError
exception FloatingPointError
exception GeneratorExit
exception ImportError
exception ModuleNotFoundError
Une sous-classe de ImportError qui est levée par import lorsqu'un module
n'a pas pu être localisé. Elle est généralement levée quand None est trouvé
dans sys.modules.
exception IndexError
exception KeyError
Levée lorsqu'une clef (de dictionnaire) n'est pas trouvée dans l'ensemble
des clefs existantes.
exception KeyboardInterrupt
exception MemoryError
exception NameError
Levée lorsqu'un nom local ou global n'est pas trouvé. Ceci ne s'applique
qu'aux noms non qualifiés. La valeur associée est un message d'erreur qui
inclut le nom qui n'a pas pu être trouvé.
exception NotImplementedError
Note
Elle ne devrait pas être utilisée pour indiquer qu'un opérateur ou qu'une
méthode n'est pas destiné à être pris en charge du tout -- dans ce cas,
laissez soit l'opérateur / la méthode non défini, soit, s'il s'agit d'une sous-
classe, assignez-le à None.
Note
exception OSError([arg])
Cette exception est levée lorsqu'une fonction système retourne une erreur
liée au système, incluant les erreurs entrées-sorties telles que "fichier non
trouvé" ou "disque plein" (pas pour les types d'arguments illégaux ou
d'autres erreurs accidentelles).
errno
winerror
strerror
filename
filename2
exception OverflowError
Levée lorsque le résultat d'une opération arithmétique est trop grand pour
être représenté. Cela ne peut pas se produire pour les entiers (qui préfèrent
lever MemoryError plutôt que d'abandonner). Cependant, pour des raisons
historiques, OverflowError est parfois levée pour des entiers qui sont en
dehors d'une plage requise. En raison de l'absence de normalisation de la
gestion des exceptions de virgule flottante en C, la plupart des opérations
en virgule flottante ne sont pas vérifiées.
exception RecursionError
exception ReferenceError
Cette exception est levée lorsqu'un pointeur faible d'un objet proxy, créé
par la fonction weakref.proxy(), est utilisé pour accéder à un attribut du
référent après qu'il ait été récupéré par le ramasse-miettes. Pour plus
d'informations sur les pointeurs faibles, voir le module weakref.
exception RuntimeError
Levée lorsqu'une erreur qui n'appartient à aucune des autres catégories est
détectée. La valeur associée est une chaîne de caractères indiquant
précisément ce qui s'est mal passé.
exception StopIteration
Modifié dans la version 3.7: Active PEP 479 pour tout le code par
défaut : quand une erreur StopIteration est levée dans un générateur elle
est transformée en une RuntimeError.
exception StopAsyncIteration
exception SyntaxError
Les instances de cette classe ont des attributs filename, lineno, offset et
text pour accéder plus facilement aux détails. La représentation str() de
l'instance de l'exception retourne seulement le message.
exception IndentationError
exception TabError
exception SystemError
179
PYTHON
exception SystemExit
code
exception TypeError
Cette exception peut être levée par du code utilisateur pour indiquer
qu'une tentative d'opération sur un objet n'est pas prise en charge, et n'est
180
PYTHON
pas censée l'être. Si un objet est destiné à prendre en charge une opération
donnée mais n'a pas encore fourni une implémentation, lever
NotImplementedError est plus approprié.
Le passage d'arguments du mauvais type (e.g. passer une list quand un int
est attendu) devrait résulter en un TypeError, mais le passage d'arguments
avec la mauvaise valeur (e.g. un nombre en dehors des limites attendues)
devrait résulter en une ValueError.
exception UnboundLocalError
Levée lorsqu'une référence est faite à une variable locale dans une
fonction ou une méthode, mais qu'aucune valeur n'a été liée à cette
variable. C'est une sous-classe de NameError.
exception UnicodeError
encoding
reason
object
start
end
exception UnicodeEncodeError
exception UnicodeDecodeError
exception UnicodeTranslateError
exception ValueError
exception ZeroDivisionError
exception EnvironmentError
exception IOError
exception WindowsError
Les exceptions suivantes sont des sous-classes d' OSError, elles sont levées en
fonction du code d'erreur système.
exception BlockingIOError
182
PYTHON
characters_written
exception ChildProcessError
exception ConnectionError
exception BrokenPipeError
exception ConnectionAbortedError
exception ConnectionRefusedError
exception ConnectionResetError
183
PYTHON
exception FileExistsError
exception FileNotFoundError
exception InterruptedError
Modifié dans la version 3.5: Python relance maintenant les appels système
lorsqu'ils sont interrompus par un signal, sauf si le gestionnaire de signal
lève une exception (voir PEP 475 pour les raisons), au lieu de lever
InterruptedError.
exception IsADirectoryError
exception NotADirectoryError
exception PermissionError
Levée lorsqu'on essaye d'exécuter une opération sans les droits d'accès
adéquats — par exemple les permissions du système de fichiers.
Correspond à errno EACCES et EPERM.
exception ProcessLookupError
exception TimeoutError
Nouveau dans la version 3.3: Toutes les sous-classes d'OSError ci-dessus ont été
ajoutées.
Voir aussi
7.1.7 Avertissements
exception Warning
exception UserWarning
exception DeprecationWarning
exception PendingDeprecationWarning
exception SyntaxWarning
exception RuntimeWarning
exception FutureWarning
exception ImportWarning
Classe de base pour les avertissements sur des erreurs probables dans les
importations de modules.
exception UnicodeWarning
exception BytesWarning
exception ResourceWarning
BaseException
+-- SystemExit
+-- KeyboardInterrupt
+-- GeneratorExit
+-- Exception
+-- StopIteration
+-- StopAsyncIteration
+-- ArithmeticError
| +-- FloatingPointError
186
PYTHON
| +-- OverflowError
| +-- ZeroDivisionError
+-- AssertionError
+-- AttributeError
+-- BufferError
+-- EOFError
+-- ImportError
| +-- ModuleNotFoundError
+-- LookupError
| +-- IndexError
| +-- KeyError
+-- MemoryError
+-- NameError
| +-- UnboundLocalError
+-- OSError
| +-- BlockingIOError
| +-- ChildProcessError
| +-- ConnectionError
| | +-- BrokenPipeError
| | +-- ConnectionAbortedError
| | +-- ConnectionRefusedError
| | +-- ConnectionResetError
| +-- FileExistsError
| +-- FileNotFoundError
| +-- InterruptedError
| +-- IsADirectoryError
| +-- NotADirectoryError
| +-- PermissionError
| +-- ProcessLookupError
| +-- TimeoutError
+-- ReferenceError
+-- RuntimeError
| +-- NotImplementedError
| +-- RecursionError
+-- SyntaxError
| +-- IndentationError
| +-- TabError
+-- SystemError
+-- TypeError
+-- ValueError
| +-- UnicodeError
| +-- UnicodeDecodeError
| +-- UnicodeEncodeError
187
PYTHON
| +-- UnicodeTranslateError
+-- Warning
+-- DeprecationWarning
+-- PendingDeprecationWarning
+-- RuntimeWarning
+-- SyntaxWarning
+-- UserWarning
+-- FutureWarning
+-- ImportWarning
+-- UnicodeWarning
+-- BytesWarning
+-- ResourceWarning
7.2. Gérer les exceptions en Python avec try, except, else et finally
Python nous fournit des structures permettant de gérer manuellement certaines
exceptions. Nous allons voir comment mettre en place ces structures dans cette
leçon.
Les clauses try et except fonctionnent ensemble. Elles permettent de tester (try)
un code qui peut potentiellement poser problème et de définir les actions à
prendre si une exception est effectivement rencontrée (except).
Le but de notre script va être de calculer le quotient de ces deux nombres entiers.
Ici, on peut déjà anticiper des cas d’erreurs qui peuvent se présenter :
l’utilisateur peut nous envoyer autre chose qu’un nombre entier ou peut nous
envoyer un dénominateur égal à 0, ce qui est interdit en mathématique.
On va vouloir gérer ces deux cas exceptionnels. Pour cela, on va pouvoir utiliser
deux blocs try et except comme cela :
188
PYTHON
Ici, on place le code à tester à l’intérieur du bloc try. Si aucune erreur n’est
détectée par Python lors de l’exécution du code, c’est-à-dire si aucun objet
exception n’est créé, ce qui se situe dans la clause except va être ignoré.
189
PYTHON
Notre code ci-dessus est cependant loin d’être optimise car notre clause except
est bien trop large. Lorsqu’on gère les exceptions manuellement, on voudra
toujours apporter la gestion la plus fine possible pour éviter de capturer toutes
les erreurs n’importe comment.
Pour cela, nous allons préciser le type d’erreur qu’une instruction except doit
intercepter. Si on souhaite gérer plusieurs types d’exceptions, on pourra préciser
autant d’instructions except qu’on le souhaite à la suite d’un try.
Ce code est déjà beaucoup plus optimisé puisqu’il nous permet une gestion plus
fine des erreurs et ne va en l’occurence capturer que deux types d’exceptions : le
cas où les données entrées ne sont pas des entiers et le cas où le dénominateur
est égal à 0.
Notez que rien ne nous empêche de préciser un except sans classe à la fin si on
souhaite absolument donner des ordres dans le cas où Python capturerait tout
autre type d’exceptions que ceux correspondant aux clauses except précédentes.
Nous allons également pouvoir ajouter une clause else en fin d’instruction try…
except. Le code contenu dans cette clause sera exécuté dans le cas où aucune
exception n’a été levée par la clause try.
La dernière clause à connaitre est la clause fin ally. Le code qu’elle contient sera
exécuté dans tous les cas, qu’une exception ait été levée par la clause try ou pas.
Cette clause va s’avérer très utile lorsqu’on voudra terminer certaines opérations
(fermer un fichier par exemple) quel que soit l’état du script.
Pour finir, vous devez savoir que Python nous laisse la possibilité de créer nos
propres classes d’exception.
Pour cela, nous allons toujours créer des classes à partir de la classe de base
Exception.
Définir nos propres exceptions va s’avérer être une fonctionnalité très utile
notamment dans le cas où on souhaite distribuer un module Python et que
certaines de nos fonctions peuvent déclencher des exceptions non prises en
charge par les classes d’exception standard Python.
Si Python est simple à apprendre, il n’en est pas moins puissant et versatile : ce
langage peut être utilisé pour effectuer des tâches complexes et pour mener à
bien différents projets très différents, que ce soit la création d’applications Web
ou de programmes divers.
Dans ce cours, nous avons passé en revue les éléments du langage Python à
connaitre : variables, structures de contrôle, fonctions, l’orienté objet, la prise en
charge des erreurs, l’intégration de modules et la manipulation de fichiers.
Avec un peu d’imagination, ces éléments vont vous permettre de créer des
projets déjà relativement complexes.