Initiation à la Programmation Python
Initiation à la Programmation Python
Avant-propos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
1 Introduction à Python . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
1.1 Présentation de Python : origines et applications . . . . . . . . . . . . . . . . . . . 13
1.1.1 Origines de Python . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
1.1.2 Caractéristiques de Python . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
1.1.3 Applications de Python . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
2.3 Entrées/sorties . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
2.3.1 Fonction print() : paramètres sep, end . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
2.3.2 Fonction input() : lecture de chaînes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
3 Structures de contrôle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
3.1 Opérateurs de comparaison et logiques . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
3.1.1 Opérateurs de comparaison . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
3.1.2 Opérateurs logiques . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
3.1.3 Opérateur in . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
3.3 Boucles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
3.3.1 Boucle for et fonction range() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
3.3.2 Boucle while . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
4 Collections de données . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
4.1 Listes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
4.1.1 Création, indexation, slicing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
4.1.2 Méthodes de listes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62
4.1.3 Listes imbriquées et copie de listes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
4.1.4 Parcours des listes avec la boucle for . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
4.2 Tuples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66
4.2.1 Création et syntaxe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
4.2.2 Immutabilité des tuples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
4.2.3 Accès aux éléments et slicing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
4.2.4 Déballage des tuples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
4.2.5 Cas d’usage des tuples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
4.2.6 Opérations sur les tuples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
4.3 Dictionnaires . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70
4.3.1 Création et syntaxe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70
4.3.2 Accès aux valeurs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
4.3.3 Modification et ajout . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
4.3.4 Suppression d’éléments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72
4.3.5 Itération sur les dictionnaires . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72
4.3.6 Comparaison avec les listes et tuples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73
4.4 Ensembles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73
4.4.1 Création et syntaxe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74
4.4.2 Ajout et suppression d’éléments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74
4.4.3 Opérations ensemblistes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75
4.4.4 Tests d’appartenance et relations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75
4.4.5 Frozenset : ensembles immuables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76
4.4.6 Cas d’usage des ensembles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76
5 Fonctions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81
5.1 Définition et appel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81
5.2 Paramètres . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82
5.2.1 Paramètres positionnels, mot-clé, valeurs par défaut . . . . . . . . . . . . . . . . . . . . . . . 83
5.2.2 Paramètres variables : *args, **kwargs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85
6 Modules et fichiers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99
6.1 Modules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99
6.1.1 Syntaxe : import, from, as . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99
6.1.2 Modules standards . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101
6.1.3 Obtenir de l’aide sur les modules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106
6.1.4 Modules externes : installation avec pip . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108
Prérequis
Aucun prérequis en programmation n’est requis pour suivre ce cours. Une familiarité de base avec
l’utilisation d’un ordinateur et des notions en algorithmique suffisent.
• Expérimentez : Testez les exemples de code fournis et modifiez-les pour mieux comprendre
leur fonctionnement.
• Posez des questions : Les erreurs sont une partie normale de l’apprentissage. Analysez les
messages d’erreur et cherchez des solutions.
• Progressez à votre rythme : Chaque concept s’appuie sur les précédents. Assurez-vous de
maîtriser les bases avant de passer aux notions avancées.
• Utilisez les ressources : Consultez la documentation officielle ou des plateformes comme
12
1. [Link]
2. [Link]
Si la commande échoue (généralement sur Windows), vérifiez que Python est ajouté au
PATH.
Note. Sur certains systèmes, la commande python peut correspondre à Python 2 ou ne pas
être reconnue. Utilisez python3 pour garantir l’exécution de Python 3. De plus, assurez-vous
de télécharger Python depuis [Link] pour éviter des versions
non officielles ou des logiciels malveillants.
Pour exécuter ce programme, enregistrez le fichier puis cliquez sur le bouton Run (triangle en haut
à droite) ou utilisez F5. La sortie s’affiche dans le terminal intégré :
Bienvenue dans ce cours de Python !
Un shell interactif est un environnement qui exécute chaque instruction dès qu’elle est saisie,
affiche le résultat puis attend la prochaine instruction. Il est idéal pour expérimenter et apprendre
les bases du langage.
Observations :
• L’instruction 2 + 3 affiche directement 5, car le shell évalue les expressions et montre leur
résultat.
• La création de la variable message ne produit pas de sortie, mais print(message) affiche le
contenu.
• Après avoir calculé aire, taper aire affiche sa valeur, car le shell affiche automatiquement
la valeur d’une variable ou d’une expression.
Le shell est souvent utile pour :
• Tester des calculs ou des fonctions rapidement.
• Vérifier la syntaxe d’une instruction avant de l’ajouter à un programme.
Note. Les instructions saisies dans le shell ne sont pas sauvegardées. Pour conserver votre code,
utilisez un fichier .py. Le shell est idéal pour des tests temporaires, tandis que les fichiers sont
adaptés aux programmes réutilisables.
Note. Les commentaires doivent être concis et pertinents. Trop de commentaires inutiles peuvent
encombrer le code. Utilisez-les pour clarifier des intentions complexes ou des choix spécifiques.
1.5.2 L’indentation
L’indentation est une caractéristique distinctive de Python : elle délimite les blocs de code, comme
les corps des boucles, des conditions ou des fonctions. Contrairement à d’autres langages qui
utilisent des accolades ({}), Python utilise des espaces ou des tabulations pour indiquer la hiérarchie
des instructions. Une indentation standard est de quatre espaces par niveau.
Un bloc de code ou bloc d’instructions est un ensemble d’instructions regroupées sous une même
structure, comme une condition ou une boucle. En Python, toutes les instructions d’un bloc doivent
avoir le même niveau d’indentation.
L’indentation signifie décaler certaines lignes de code vers la droite en ajoutant des espaces (ou
des tabulations) au début de la ligne. C’est une règle obligatoire en Python : elle sert à montrer
visuellement quels morceaux de code sont liés ensemble. Même si pour l’instant nous n’avons pas
encore vu les cas où elle est nécessaire (comme les conditions ou les répétitions), il est important
de savoir qu’en Python, l’indentation sert à organiser le code de manière visuelle et fonctionnelle,
garantissant que l’interpréteur Python comprenne quelles instructions appartiennent à un même
groupe. Oublier l’indentation ou se tromper empêche le programme de fonctionner.
Note. Une indentation incorrecte provoque une erreur (IndentationError). Par exemple, mélanger
des espaces et des tabulations ou indenter une ligne de manière incohérente interrompt l’exécution.
Un traceback est un rapport généré par Python lorsqu’une erreur survient, montrant la pile d’appels
(les instructions exécutées) et des détails sur l’erreur. Lire le traceback est essentiel pour identifier
et corriger les problèmes.
Exécution :
File "[Link]", line 2
print("Bonjour"
^
SyntaxError: '(' was never closed
Analyse :
• Le message indique une SyntaxError à la ligne 2.
• La cause est '(' was never closed, signifiant qu’une parenthèse a été ouverte et n’a jamais
été fermée.
Pour corriger cette erreur, il suffit d’ajouter la parenthèse fermante.
Exécution :
Traceback (most recent call last):
File "[Link]", line 2, in <module>
print(age)
^^^
NameError: name 'age' is not defined
Analyse :
• Le message indique une NameError à la ligne 2.
• La cause est name 'age' is not defined, car la variable age n’a pas été définie avant
d’être utilisée.
Note. Une NameError peut aussi survenir si vous faites une faute de frappe (par exemple, Age au
lieu de age, car Python est sensible à la casse) ou si vous utilisez une variable dans un mauvais
contexte.
Considérons ce programme :
1 # Programme avec une TypeError
2 nombre = 5
3 texte = "Bonjour"
4 resultat = nombre + texte
5 print(resultat)
Exécution :
Traceback (most recent call last):
File "[Link]", line 4, in <module>
resultat = nombre + texte
~~~~~~~^~~~~~~
TypeError: unsupported operand type(s) for +: 'int' and 'str'
Analyse :
• Le message indique une TypeError à la ligne 4.
• La cause est unsupported operand type(s) for +: 'int' and 'str', car Python ne
peut pas additionner un entier (int) et une chaîne (str).
Pour corriger ce type d’erreur, il est important de vérifier que les deux éléments que l’on veut
additionner sont du même type. Dans cet exemple, on pourrait soit convertir le nombre en chaîne
de caractères, soit convertir la chaîne en nombre (si c’est possible et logique). La conversion de
type ("transtypage" ou "casting") permet de transformer une valeur d’un type vers un autre.
Après avoir exploré les bases de Python, comme la syntaxe et les erreurs courantes, il est temps
de plonger dans les concepts fondamentaux qui permettent de manipuler des données dans un
programme. Ce chapitre se concentre sur les variables, les types de données et les mécanismes
d’entrées/sorties. Ces notions sont essentielles pour construire des programmes capables de stocker,
traiter et afficher des informations.
L’affectation est l’action d’associer une valeur à une variable avec l’opérateur =. Le nom de la
variable est à gauche et la valeur (ou une expression) est à droite. Une variable peut être réaffectée
à une nouvelle valeur à tout moment.
Pour que les noms de variables soient valides et conformes aux bonnes pratiques, respectez ces
règles :
• Caractères autorisés : Lettres (a-z, A-Z), chiffres (0-9) et underscores (_). Les noms ne
peuvent pas commencer par un chiffre.
24 Chapitre 2. Variables, types et entrées/sorties
Une variable peut être réaffectée à une nouvelle valeur et son type peut changer grâce au typage
dynamique. Cela simplifie l’écriture du code, mais nécessite de faire attention aux types lors des
opérations.
Testons la réaffectation dans le shell interactif :
>>> x = 10 # x est un entier
>>> x
10
>>> x = "Python" # x devient une chaîne
>>> x
'Python'
• Choisissez des noms qui reflètent la signification de la variable (par exemple, salaire_mensuel
plutôt que s).
• Évitez de réaffecter une variable à un type complètement différent dans le même programme,
sauf si cela est justifié, pour maintenir la clarté.
• Initialisez les variables avant de les utiliser pour éviter une NameError.
1. [Link]
Un type de données définit les caractéristiques d’une valeur, telles que sa représentation, sa taille
en mémoire et les opérations autorisées. Le typage dynamique de Python attribue automatiquement
le type lors de l’affectation.
>>> entier = 42 # Type int
>>> entier
42
>>> decimal = 3.14159 # Type float
>>> decimal
3.14159
>>> texte = "Python" # Type str
>>> texte
'Python'
>>> vrai_ou_faux = True # Type bool
>>> vrai_ou_faux
True
• Entiers (int) : Représentent des nombres entiers positifs, négatifs ou zéro. Python 3 gère
des entiers de taille arbitraire, sans limite pratique (par exemple, 12345678901234567890
reste valide).
• Nombres à virgule (float) : Représentent des nombres décimaux. Notez que les float
peuvent introduire des approximations dans certains calculs (par exemple, 0.1 + 0.2 donne
0.30000000000000004 en raison de la représentation en virgule flottante 2 ).
• Chaînes (str) : Représentent du texte, délimité par des guillemets simples (' ') ou doubles
(" "), parfois par des docstrings. Les chaînes sont utilisées pour afficher des messages,
manipuler des données textuelles ou interagir avec l’utilisateur.
• Booléens (bool) : Représentent deux valeurs : True (vrai) ou False (faux). Ils sont utilisés
dans les conditions et les tests logiques.
La fonction type() retourne le type d’une valeur ou d’une variable. C’est un outil précieux pour
diagnostiquer des erreurs ou vérifier le comportement du typage dynamique.
>>> x = 100
>>> type(x)
<class 'int'>
>>> x = 2.718
>>> type(x)
<class 'float'>
>>> x = "Bonjour"
>>> type(x)
<class 'str'>
>>> x = False
>>> type(x)
<class 'bool'>
Cela montre comment type() révèle le type actuel de x après chaque affectation.
2. [Link]
• Vérifiez les types avec type() si une opération échoue de manière inattendue.
• Soyez conscient des limites des float pour les calculs nécessitant une haute précision.
• Utilisez des noms de variables qui suggèrent leur type (par exemple, distance_km pour un
float, nom_utilisateur pour un str).
Un opérateur arithmétique est un symbole (comme + ou *) qui effectue une opération mathéma-
tique sur deux opérandes (valeurs ou variables). Le résultat dépend des types des opérandes (int
ou float).
Les opérateurs sont évalués selon leur priorité, mais vous pouvez utiliser des parenthèses () pour
forcer un ordre spécifique, comme en mathématiques.
>>> 2 + 3 * 4 # * a priorité sur +
14
>>> (2 + 3) * 4 # Parenthèses changent l'ordre
20
Sans parenthèses, 3 * 4 est calculé en premier, puis + 2. Avec parenthèses, 2 + 3 est évalué
d’abord.
Note. Omettre des parenthèses dans une expression complexe peut donner un résultat inattendu.
Par exemple, 10 / 2 * 5 donne 25.0, car / et * ont la même priorité et sont évalués de gauche à
droite. Utilisez des parenthèses pour clarifier vos intentions, comme 10 / (2 * 5) pour obtenir
1.0.
Les opérateurs peuvent être appliqués à des variables, ce qui est courant dans des programmes plus
structurés.
1 # Calcul de la surface d'un rectangle
2 longueur = 6
3 largeur = 4
4 surface = longueur * largeur
5 print(surface)
24
Ici, * est utilisé pour multiplier les valeurs des variables longueur et largeur.
En plus des opérateurs arithmétiques de base, Python propose des opérateurs d’affectation
composée qui combinent une opération arithmétique avec une affectation. Ces opérateurs, comme
+=, −=, *=, /=, //=, %= et **=, permettent de modifier une variable en place.
Un opérateur d’affectation composée effectue une opération arithmétique sur une variable et
réassigne le résultat à cette même variable.
>>> x = 10
>>> x += 5 # Équivaut à x = x + 5
>>> x
15
>>> x *= 2 # Équivaut à x = x * 2
>>> x
30
>>> x /= 3 # Équivaut à x = x / 3
>>> x
10.0
>>> x //= 2 # Équivaut à x = x // 2
>>> x
5.0
Note. Les opérateurs d’affectation composée modifient la variable directement. Assurez-vous que
la variable est définie avant de l’utiliser.
8.0
>>> 5 + "3" # int + str
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for +: 'int' and 'str'
La conversion de type est l’opération qui change le type d’une valeur, en utilisant une fonction
comme int() ou str(). Elle est nécessaire lorsque les types des opérandes ne sont pas compatibles
avec l’opération souhaitée.
• int(x) : Convertit x en entier. Accepte des float (en tronquant la partie décimale), des str
représentant des entiers (par exemple, "123") ou des bool.
• float(x) : Convertit x en nombre à virgule. Accepte des int, des str représentant des
nombres (par exemple, "3.14") ou des bool.
• str(x) : Convertit x en chaîne. Fonctionne avec tous les types (int, float, bool).
• bool(x) : Convertit x en booléen. Les règles sont spécifiques (voir ci-dessous).
>>> int(3.7) # float vers int (tronque)
3
>>> float("2.5") # str vers float
2.5
>>> str(42) # int vers str
'42'
>>> bool(0) # int vers bool
False
Observations :
• int(3.7) tronque la partie décimale, donnant 3.
• float("2.5") convertit la chaîne "2.5" en 2.5.
• str(42) produit la chaîne "42".
• bool(0) donne False, car 0 est considéré comme faux.
>>> bool("Python")
True
La notation scientifique est utilisée pour représenter des nombres très grands ou très petits de
manière compacte, en utilisant un exposant. En Python, un nombre en notation scientifique s’écrit
sous la forme aEb, où a est la mantisse, E (ou e) indique l’exposant et b est la puissance de 10.
>>> 1.5e3 # 1.5 x 10^3
1500.0
>>> 2.7e−2 # 2.7 x 10^(−2)
0.027
>>> −4e5 # −4 x 10^5
−400000.0
Observations :
• Les résultats sont des float, même si on ne met que des entiers à gauche et à droite du
symbole e.
• e peut être suivi d’un exposant positif ou négatif.
Depuis Python 3.6, le séparateur _ peut être utilisé pour améliorer la lisibilité des nombres longs,
qu’ils soient en notation décimale, scientifique ou autre. Les underscores sont ignorés par l’interpré-
teur et servent uniquement à grouper visuellement les chiffres, comme des virgules ou des espaces
dans l’écriture manuelle.
>>> 10_000_000
10000000
>>> 1_234.56_78
1234.5678
Le séparateur _ rend les nombres composés de beaucoup de chiffres beaucoup plus lisibles, surtout
dans les calculs scientifiques ou financiers.
Note. Le séparateur _ ne change pas la valeur du nombre. Cependant, il ne peut pas être placé au
début, à la fin ou consécutivement (par exemple, 123_ ou 123__456 provoque une SyntaxError).
Une chaîne de caractères est une séquence de caractères (lettres, chiffres, symboles) entourée de
guillemets simples (') ou doubles ("). Les chaînes sont immuables, c’est-à-dire que leur contenu ne
peut pas être modifié après création.
Une chaîne est définie en plaçant du texte entre guillemets simples (') ou doubles ("). Les deux
sont équivalents, mais le choix peut dépendre du contenu de la chaîne. Jetons un œil à l’exemple
ci-dessous.
>>> "Bonjour"
'Bonjour'
>>> 'Python 3'
'Python 3'
>>> message = "C'est une chaîne"
>>> message
"C'est une chaîne"
Si une chaîne contient des guillemets, utilisez l’autre type de délimiteur ou un caractère d’échappe-
ment.
Les caractères d’échappement permettent d’inclure des caractères spéciaux (comme des guille-
mets ou des retours à la ligne) dans une chaîne en utilisant une barre oblique inverse (\). Les plus
courants sont :
• \n : Retour à la ligne.
• \t : Tabulation.
• \" ou \' : Guillemet double ou simple.
• \\ : Barre oblique inverse (antislash).
Note. Oublier un caractère d’échappement pour un guillemet dans une chaîne provoque une
SyntaxError. Par exemple, "Il dit "Python"" est incorrect. Utilisez donc l’échappement ou
changez les délimiteurs ('Il dit "Python"').
Les chaînes brutes désactivent l’interprétation des caractères d’échappement en ajoutant un r avant
les guillemets. Elles sont utiles pour des expressions comme des chemins de fichiers (Windows) ou
des expressions régulières 3 .
>>> print("C:\\nouveau\\dossier")
C:\nouveau\dossier
>>> print(r"C:\nouveau\dossier")
C:\nouveau\dossier
Dans une chaîne normale, \n est interprété comme un retour à la ligne. Dans une chaîne brute (r),
\nest traité littéralement.
Note. Les chaînes brutes ne peuvent pas se terminer par une barre oblique inverse seule (r"texte\"
provoque une SyntaxError). Utilisez des chaînes normales ou doublez la barre (r"texte\\") si
nécessaire.
Les chaînes multilignes, entourées de triples guillemets (''' ou """), permettent d’écrire du texte
sur plusieurs lignes sans utiliser \n explicitement.
>>> texte = '''Ligne 1
... Ligne 2
... Ligne 3
... Ligne 4
... Ligne 5
... '''
>>> print(texte)
Ligne 1
Ligne 2
Ligne 3
Ligne 4
Ligne 5
[Link] Concaténation
3. [Link]
[Link] Répétition
La répétition utilise l’opérateur * pour répéter une chaîne un nombre donné de fois.
>>> prenom = "Alice"
>>> prenom * 5
'AliceAliceAliceAliceAlice'
[Link] Indexation
L’indexation permet d’accéder à un caractère spécifique d’une chaîne en utilisant son indice, noté
entre crochets [i]. Les indices commencent à 0 pour le premier caractère et peuvent être négatifs
pour compter à partir de la fin (−1 est le dernier caractère). L’indexation extrait un caractère à
l’indice donné, retournant une nouvelle chaîne d’un seul caractère.
>>> texte = "Python"
>>> texte[0]
'P'
>>> texte[2]
't'
>>> texte[−1]
'n'
>>> texte[−3]
'h'
Note. Accéder à un indice inexistant provoque une IndexError. Par exemple, texte[10] pour
texte = "Python" échoue, car la chaîne a seulement 6 caractères (indices de 0 à 5).
Le découpage (ou slicing) permet d’extraire une sous-chaîne à partir d’une chaîne en spécifiant une
plage d’indices, c’est-à-dire une partie d’une chaîne de caractères. Pour le faire, on a les différentes
syntaxes suivantes :
• chaine[début:fin]} : Extrait les caractères de l’indice début (inclus) à l’indice fin (exclu).
• chaine[:fin] : Extrait les caractères du début jusqu’à l’indice fin (exclu).
• chaine[début:] : Extrait les caractères de l’indice début (inclus) jusqu’à la fin.
• chaine[début:fin:pas] : Extrait les caractères de l’indice début (inclus) à l’indice fin
(exclu) avec un pas spécifié.
>>> texte = "Programmation"
>>> texte[0:4] # Du 1er au 4e caractère
'Prog'
>>> texte[4:8] # Du 5e au 8e caractère
'ramm'
>>> texte[:5] # Du début au 5e caractère
'Progr'
>>> texte[8:] # Du 9e caractère à la fin
'ation'
>>> texte[::2] # Tous les caractères, un sur deux
'Pormain'
>>> texte[::−1] # Tous les caractères, dans l'ordre inverse
'noitammargorP'
Note. Les chaînes sont immuables : vous ne pouvez pas modifier un caractère via l’indexation (par
exemple, texte[0] = 'X' provoque une TypeError).
Les chaînes Python disposent de nombreuses méthodes intégrées pour les manipuler. Les plus
courantes pour le traitement de texte sont listées dans le tableau 2.1.
Voici quelques illustrations de ces méthodes :
>>> texte = " Bonjour, Python ! "
>>> print([Link]())
bonjour, python !
>>> print([Link]())
BONJOUR, PYTHON !
>>> print([Link]())
Bonjour, Python !
>>> print([Link]("Python"))
11
>>> print([Link]("Java"))
−1
>>> print([Link]("Python", "Java"))
Bonjour, Java !
>>> mots = [Link]()
>>> print(mots)
['Bonjour,', 'Python', '!']
>>> phrase = "−".join(mots)
>>> print(phrase)
Bonjour,−Python−!
Dans cet exemple, strip() supprime les espaces autour de la chaîne, find("Python") retourne
l’indice 10, split() divise la chaîne en mots et join() recombine les mots avec un tiret comme
séparateur.
Notes.
1. Les méthodes comme lower(), strip() ou replace() ne modifient pas la chaîne originale,
car les chaînes sont immuables. Elles retournent une nouvelle chaîne modifiée. Pour conserver
le résultat, affectez-le à une variable, par exemple : texte = [Link]().
2. Il existe une multitude de méthodes permettant d’effectuer des traitements sur les chaînes.
Pour plus de détails, consultez la documentation officielle sur les méthodes des chaînes de
caractères 4 .
4. [Link]
TABLE 2.1 – Méthodes courantes des chaînes Python pour le traitement de texte
Méthode Description
lower() Convertit tous les caractères alphabétiques en minuscules (par
exemple, "Bonjour" devient "bonjour").
upper() Convertit tous les caractères alphabétiques en majuscules (par
exemple, "Bonjour" devient "BONJOUR").
islower() Retourne True si tous les caractères alphabétiques sont en minus-
cules et qu’il y a au moins un caractère alphabétique, sinon False.
isupper() Retourne True si tous les caractères alphabétiques sont en majus-
cules et qu’il y a au moins un caractère alphabétique, sinon False.
isdecimal() Retourne True si tous les caractères sont des chiffres décimaux
(0-9), sinon False (par exemple, "123" retourne True, "12a"
retourne False).
isdigit() Retourne True si tous les caractères sont des chiffres (inclut des
chiffres Unicode), sinon False. Similaire à isdecimal(), mais
plus large.
isalpha() Retourne True si tous les caractères sont alphabétiques (lettres
uniquement) et qu’il y a au moins un caractère, sinon False.
isalnum() Retourne True si tous les caractères sont alphanumériques (lettres
ou chiffres) et qu’il y a au moins un caractère, sinon False.
capitalize() Convertit la première lettre en majuscule et le reste en minuscules
(par exemple, "bonjour" devient "Bonjour").
title() Convertit la première lettre de chaque mot en majuscule et le reste
en minuscules (par exemple, "bonjour tout le monde" devient
"Bonjour Tout Le Monde").
swapcase() Inverse la casse : les minuscules deviennent majuscules et vice
versa (par exemple, "Bonjour" devient "bONJOUR").
strip() Supprime les espaces et les caractères de saut de ligne (\n, \t) au
début et à la fin de la chaîne.
rstrip() Supprime les espaces et les caractères de saut de ligne à la fin de
la chaîne uniquement.
find(sub)| Retourne l’indice de la première occurrence de la sous-chaîne sub
dans la chaîne, ou −1 si sub n’est pas trouvé.
replace(ancien, nouveau) Remplace toutes les occurrences de la sous-chaîne ancien par
nouveau dans la chaîne.
split(sep) Divise la chaîne en une liste de sous-chaînes, en utilisant sep
comme délimiteur (par exemple, "a,b,c".split(",") donne ['
a', 'b', 'c']).
join(iterable) Concatène les éléments d’un itérable (par exemple, une liste) en
une seule chaîne, en utilisant la chaîne comme séparateur (par
exemple, ",".join(['a', 'b', 'c']) donne "a,b,c").
messages lisibles.
Le formatage consiste à intégrer des valeurs dans une chaîne en utilisant des espaces réservés ou
des expressions. Cela améliore la lisibilité par rapport à la concaténation manuelle.
La méthode format() insère des valeurs dans une chaîne en remplaçant des espaces réservés {}.
Les valeurs sont passées comme arguments à format().
1 # Formatage avec format()
2 nom = "Bob"
3 age = 25
4 message = "Bonjour, {} ! Vous avez {} ans.".format(nom, age)
5 print(message)
Vous pouvez spécifier des indices dans les espaces réservés pour contrôler l’ordre ou réutiliser des
valeurs.
>>> "x={1}, y={0}, x+y={2}".format(3, 4, 7)
'x=4, y=3, x+y=7'
{1} prend la deuxième valeur (4), {0} la première (3) et {2} la troisième (7).
[Link] F-strings
Les f-strings, ou littérales de chaînes formatées, introduites en Python 3.6, offrent une méthode
concise pour intégrer des valeurs et des expressions directement dans une chaîne de caractères.
En préfixant une chaîne par f ou F, vous pouvez insérer des expressions entre accolades {}, qui
sont évaluées à l’exécution et remplacées par leurs résultats. Cette approche est plus lisible que la
concaténation ou la méthode format(), car elle permet d’écrire le code de manière naturelle, en
plaçant les variables ou expressions exactement là où elles apparaissent dans le texte. Les f-strings
sont adaptées pour créer des messages dynamiques, comme des affichages personnalisés.
>>> prenom = "Charlie"
>>> note = 15.5
>>> print(f"{prenom} a obtenu {note}/20 à l'examen.")
Charlie a obtenu 15.5/20 à l'examen.
>>> x = 10
>>> y = 20
>>> f"Somme : {x + y}"
'Somme : 30'
Dans le premier exemple, prenom et note sont insérés directement dans la chaîne. Dans le second,
l’expression x + y est évaluée et le résultat 30 est intégré. Les f-strings permettent ainsi d’inclure
non seulement des variables, mais aussi des calculs ou des appels de fonctions.
Une limitation importante est que les f-strings ne peuvent pas être vides ou contenir des accolades
non appariées. Par exemple, f"{}" provoquent une SyntaxError, car l’interpréteur attend une
expression valide entre les accolades. Si on veut afficher des accolades littérales avec les f-strings,
Le formatage des f-strings permet de personnaliser la présentation des valeurs, comme l’alignement,
la précision des nombres ou l’affichage de formats spécifiques (par exemple, pourcentages ou
hexadécimal). En ajoutant un spécificateur de format après une expression, séparé par deux-points
(:), vous pouvez contrôler comment la valeur est affichée.
Formatage des nombres
Pour les nombres (int et float), vous pouvez spécifier la précision, ajouter des séparateurs de
milliers ou utiliser des notations comme la notation scientifique ou les pourcentages.
>>> pi = 3.1415926535
>>> print(f"Pi arrondi: {pi:.2f}")
Pi arrondi: 3.14
>>> nombre = 1234567
>>> print(f"Nombre formaté: {nombre:,}")
Nombre formaté: 1,234,567
>>> print(f"Nombre formaté e: {nombre:.3e}")
Nombre formaté e: 1.235e+06
>>> pourcentage = 0.378
>>> print(f"Taux: {pourcentage:.1%}")
Taux: 37.8%
Explications :
• {pi:.2f} affiche pi avec deux décimales, arrondi à 3.14.
• {nombre:,} ajoute des virgules comme séparateurs de milliers.
• {nombre:.3e} écrit nombre en notation scientifique.
• {pourcentage:.1%} convertit 0.378 en pourcentage avec une décimale, soit 37.8%.
Alignement et remplissage
Les f-strings permettent de contrôler l’alignement (< pour gauche, > pour droite, ^ pour centré) et
d’ajouter un caractère de remplissage pour atteindre une largeur donnée. Par défaut, l’espace est le
caractère qui sert de remplissage.
>>> texte = "Python"
>>> print(f"Centré: |{texte:^10}|")
Centré: | Python |
>>> print(f"Rempli: |{texte:*>10}|")
Rempli: |****Python|
Explications :
• {texte:^10} centre Python dans un espace de 10 caractères, avec des espaces comme
remplissage.
• {texte:*>10} aligne à droite et remplit avec des * à gauche.
formatage dynamique.
>>> largeur = 12
>>> precision = 3
>>> valeur = 12.34567
>>> print(f"Résultat: {valeur:{largeur}.{precision}f}")
Résultat: 12.346
Ici, largeur et precision sont évalués pour définir le format 12.3f, alignant 12.346 à droite sur
12 caractères.
Notes.
1. Les spécificateurs de format doivent respecter la syntaxe correcte. Par exemple, {pi:.2g}
pour un float est valide, mais {texte:.2f} pour une chaîne provoque une ValueError.
2. Les f-strings sont généralement préférées à format() pour leur clarté et leur concision. Elles
sont particulièrement utiles pour les affichages dynamiques dans des programmes interactifs.
Par ailleurs, les possibilités offertes par les f-strings pour le formatage sont vastes : formats
numériques (hexadécimal, octal, binaire), alignements personnalisés, formats spécifiques
comme les dates, etc. Vous pouvez consulter la documentation 5 6 ou ce mémo 7 pour explorer
toutes les options et pour avoir des détails approfondis sur leur syntaxe et leurs applications.
2.3 Entrées/sorties
Les programmes Python ne se contentent pas d’effectuer des calculs internes : ils interagissent
souvent avec l’utilisateur en affichant des résultats ou en collectant des données. Les opérations
d’entrées/sorties (E/S) permettent cette communication. La sortie consiste à afficher des informa-
tions, généralement à l’écran, tandis que l’entrée permet de lire des données saisies par l’utilisateur,
comme du texte ou des nombres. Ces mécanismes de base des entrées/sorties en Python sont assurés
par la fonction print() pour les sorties et la fonction input() pour les entrées.
Par défaut, print() affiche ses arguments séparés par une espace 8 et termine par un saut de ligne
(\n). Cela permet d’afficher plusieurs valeurs dans une seule instruction.
>>> nom = "Alice"
>>> age = 20
>>> print(nom, age)
Alice 20
5. [Link]
6. [Link]
7. [Link]
8. On parle de « une espace » au féminin lorsqu’il s’agit du caractère typographique (et non d’un lieu ou d’une
surface).
Ici, nom et age sont affichés avec une espace entre eux, suivie d’un saut de ligne. Le shell affiche
chaque appel à print() sur une nouvelle ligne.
Le paramètre sep (séparateur) définit la chaîne utilisée pour séparer plusieurs arguments dans
un même appel à print(). Par défaut, sep=" " (une espace), mais vous pouvez le modifier pour
personnaliser l’affichage.
>>> print("01", "01", "1970", sep="−")
01−01−1970
>>> print("x", "y", "z", sep=", ")
x, y, z
Dans le premier cas, sep="−" joint les valeurs avec des tirets, simulant un format de date. Dans le
second, sep=", " utilise une virgule et une espace pour une liste claire.
Le paramètre end spécifie ce qui est ajouté à la fin de l’affichage. Par défaut, end="\n" (saut de
ligne), mais vous pouvez le remplacer par une autre chaîne pour modifier le comportement.
1 print("En cours", end="...")
2 print("Terminé")
En cours...Terminé
Ici, end="..." supprime le saut de ligne après "En cours" et le prochain print() continue sur la
même ligne. Sans end="...", "Terminé" aurait été affiché sur une nouvelle ligne.
La fonction input() est simple à utiliser : elle affiche le prompt (facultatif), attend la saisie de
l’utilisateur et retourne la chaîne entrée. Cette chaîne peut être stockée dans une variable pour un
traitement ultérieur.
>>> nom = input("Entrez votre nom : ")
Entrez votre nom : Alice
>>> print(f"Bonjour {nom}")
Bonjour Alice
Ici, input("Entrez votre nom : ") affiche le message, l’utilisateur tape Alice et la chaîne
"Alice" est assignée à nom. Le print() suivant utilise cette valeur pour un message personnalisé.
Puisque input() retourne toujours une chaîne, vous devez souvent convertir la saisie en un autre
type (comme int ou float) pour effectuer des calculs numériques. Cela nécessite l’utilisation des
fonctions de conversion (int(), float(), etc.).
1 # Calcul de l'âge l'année prochaine
2 age = input("Entrez votre âge : ")
3 age = int(age) # Conversion en entier
4 print(f"Dans un an, vous aurez {age + 1} ans.")
La saisie "20" est convertie en 20 (entier) avec int(), ce qui permet d’effectuer l’addition age + 1.
Il faut également noter que les lignes 2 et 3 peuvent être combinées en une seule.
1 # Calcul de l'âge l'année prochaine
2 age = int(input("Entrez votre âge : "))
3 print(f"Dans un an, vous aurez {age + 1} ans.")
De cette manière, l’entrée est directement convertie en un entier avant que sa valeur ne soit assignée
à la variable age.
Note. La conversion des saisies peut échouer si l’utilisateur entre une valeur non valide. Par
exemple, int("abc") ou float("3.14.15") provoquent une ValueError. À ce stade, supposez
que les entrées sont correctes, mais une gestion des erreurs d’entrée sera nécessaire : on ne fait
jamais confiance aux entrées utilisateur.
Jusqu’à présent, vos programmes Python ont suivi une exécution linéaire : chaque instruction était
exécutée séquentiellement, de haut en bas. Cependant, dans la réalité, les programmes doivent
souvent prendre des décisions, répéter des actions ou réagir différemment selon les données ou
les entrées utilisateur. Les structures de contrôle permettent de diriger le flux d’exécution d’un
programme en fonction de conditions ou de boucles. Ce chapitre introduit les outils fondamen-
taux pour rendre vos programmes dynamiques : les opérateurs de comparaison et logiques, les
instructions conditionnelles et les boucles. Vous apprendrez également à contrôler les boucles et à
gérer les erreurs avec une introduction aux exceptions. Ces concepts sont essentiels pour créer des
programmes interactifs, capables de s’adapter à différentes situations.
>>> x = 10
>>> y = 20
>>> x == y
False
>>> x != y
True
>>> x < y
True
>>> x >= 10
True
>>> −1 < x < 10
False
Les opérateurs de comparaison fonctionnent avec différents types, comme les nombres (int, float)
et les chaînes (str), mais leur comportement dépend du type. Pour les nombres, la comparaison
suit l’ordre mathématique. Pour les chaînes, la comparaison est lexicographique (suivant l’ordre
alphabétique.), basée sur l’ordre Unicode des caractères (par exemple, "A" précède "B" et "ananas"
précède "banane").
>>> mot1 = "chat"
>>> mot2 = "chien"
>>> mot1 < mot2
True
>>> "Z" < "a"
True
Ici, mot1 < mot2 est True, car "chat" précède "chien" dans l’ordre lexicographique. De même,
"Z" < "a" est True, car les majuscules (Unicode plus bas) précèdent les minuscules. L’ordre est
comme suit : 0−9A−Za−z puis les caractères accentués.
Note. Comparer des types différents, comme un entier et une chaîne, peut provoquer une TypeError
, sauf pour == et !=, qui retournent généralement False ou True. Par exemple, 5 == "5" retourne
False, mais 5 < "5" provoque une erreur. Assurez-vous que les opérandes sont compatibles avant
de comparer. De plus, faites bien attention à ne pas confondre l’opérateur d’affectation = qui
affecte une valeur à une variable et l’opérateur de comparaison == qui compare les valeurs de
deux variables.
False
Explications :
• age >= 18 and salaire > 20000 est True, car age >= 18 (True) et salaire > 20000
(True) sont tous deux satisfaits.
• age < 18 or salaire > 20000 est True, car salaire > 20000 est True, même si age <
18 est False.
• not (age == 25) est False, car age == 25 est True et not True donne False.
Les opérateurs logiques peuvent être combinés pour créer des conditions complexes. Pour éviter
toute ambiguïté, utilisez des parenthèses pour clarifier l’ordre d’évaluation, surtout lorsque and, or
et not sont mélangés.
Note. Les opérateurs logiques en Python utilisent une évaluation paresseuse (ou short-circuit
evaluation). Par exemple, dans A and B, si A est False, B n’est pas évalué, car le résultat sera
False quoi qu’il arrive. De même, dans A or B, si A est True, B n’est pas évalué. Cette propriété
peut améliorer les performances et éviter des erreurs, comme vérifier qu’une variable existe avant
de l’utiliser.
3.1.3 Opérateur in
L’opérateur in est un opérateur spécial qui vérifie si une valeur est présente dans une séquence,
comme une chaîne, une liste ou un tuple (les listes et tuples seront abordés dans le chapitre 4). Il
retourne True si la valeur est trouvée, False sinon. L’opérateur not in est son inverse, vérifiant
l’absence d’une valeur.
>>> texte = "Bonjour"
>>> "jour" in texte
True
>>> "soir" in texte
False
>>> "Bon" not in texte
False
Explications :
• "jour" in texte est True, car la sous-chaîne "jour" apparaît dans "Bonjour".
• "soir" in texte est False, car "soir" n’est pas présent.
• "Bon" not in texte est False, car "Bon" est bien dans "Bonjour".
Note. L’opérateur in est sensible à la casse pour les chaînes. Par exemple, "bon" in "Bonjour"
retourne False, car "bon" (minuscule) diffère de "Bon" (majuscule).
Une instruction conditionnelle évalue une condition (une expression booléenne) et exécute un
bloc de code si la condition est True. En Python, une instruction conditionnelle commence par if,
peut inclure des clauses elif (pour vérifier d’autres conditions) et se termine optionnellement par
else (pour gérer tous les cas restants).
Ici, age >= 18 est True, donc le bloc indenté sous if s’exécute et affiche le message. Si age était
inférieur à 18, rien ne s’afficherait, car il n’y a pas de else.
Puisque age >= 18 est False, le bloc sous else s’exécute. Cela garantit qu’un message est toujours
affiché, quel que soit l’âge.
• Saisie 10 :
Entrez votre note (0−20) : 10
Passable.
Explications :
• Les conditions sont testées dans l’ordre : si note >= 16 est True, "Très Bien !" s’affiche
et le reste est ignoré.
• Si note >= 16 est False, Python passe à note >= 14, et ainsi de suite.
• else capture les notes inférieures à 10.
La condition extérieure age >= 18 est testée en premier. Si elle est True, la condition imbriquée
permis == "oui" détermine le message affiché.
Notes.
1. L’indentation est très importante dans les instructions conditionnelles, ainsi que dans les
structures comme les boucles ou les fonctions, comme vous le verrez plus loin. Une mauvaise
indentation provoque une IndentationError ou change la logique du programme. Prenons,
par exemple :
1 if True:
2 print("Ceci s'exécute")
3 print("Ceci aussi") # Dans le bloc if
4 print("Ceci est hors du if")
3.3 Boucles
Les boucles permettent à un programme de répéter une série d’instructions plusieurs fois, ce qui est
essentiel pour automatiser des tâches répétitives, comme traiter une liste de données ou effectuer
des calculs itératifs. En Python, deux types de boucles principales sont utilisés : la boucle for qui
itère sur une séquence prédéfinie et la boucle while qui répète un bloc d’instructions tant qu’une
condition est vraie.
La fonction range() génère une séquence de nombres, souvent utilisée pour contrôler le nombre
d’itérations dans une boucle for. Elle peut être utilisée de trois façons :
• range(n) : Génère les nombres de 0 à n−1 avec un incrément de 1.
• range(debut, fin) : Génère les nombres de debut à fin−1 avec un incrément de 1.
• range(debut, fin, pas) : Génère les nombres de debut à fin−1 avec un incrément de
pas.
3
4
Ici, range(5) génère les nombres 0, 1, 2, 3, 4, et la variable i prend chaque valeur successive-
ment. Le bloc indenté affiche chaque nombre.
Voici un autre exemple pour compter à rebours :
>>> for seconde in range(10, 0, −1):
... print(f"T−{seconde} secondes")
... print("Décollage !")
...
T−10 secondes
T−9 secondes
...
T−1 secondes
Décollage !
Chaque caractère de "Python" est assigné à lettre et le bloc affiche chaque caractère sur une
nouvelle ligne.
Parfois, vous voulez accéder à la fois à l’élément d’une séquence et à sa position (ou index) dans
la boucle. La fonction enumerate() est un outil intégré qui génère des paires (index, élément)
pour chaque itération. Cela rend le code plus clair que l’utilisation manuelle d’un compteur. Bien
que enumerate() soit souvent utilisé avec des listes, il fonctionne parfaitement avec des chaînes
ou range().
>>> texte = "code"
>>> for index, caractere in enumerate(texte):
... print(f"Position {index} : {caractere}")
...
Position 0 : c
Position 1 : o
Position 2 : d
Position 3 : e
enumerate(texte) produit des paires (0, 'c'), (1, 'o'), (2, 'd'), (3, 'e'), décomposées
dans les variables index et caractere. Cela permet de suivre la position de chaque caractère sans
gérer un compteur manuellement.
Un détail subtil mais important concerne la variable de boucle (comme i ou lettre des exemples
précédents). Après l’exécution d’une boucle for, cette variable n’est pas supprimée ; elle conserve
la dernière valeur qu’elle a prise dans la boucle. Cela peut être utile pour vérifier l’état final, mais
cela peut aussi causer des erreurs si vous réutilisez la variable sans la réinitialiser.
Observons la persistance dans le shell :
>>> for i in range(4):
... print(i)
...
0
1
2
3
>>> print(f"Dernière valeur de i : {i}")
Dernière valeur de i : 3
Après la boucle, i vaut 3, la dernière valeur de range(4). Si la boucle est vide (par exemple,
range(0)), i n’est pas définie, ce qui peut provoquer une NameError si vous tentez de l’utiliser.
Note. La persistance de la variable de boucle peut entraîner des erreurs si vous supposez qu’elle
est réinitialisée ou non définie après la boucle. Par exemple, réutiliser i dans une autre boucle sans
le savoir peut fausser les résultats. Pour éviter cela, initialisez explicitement vos variables avant de
les utiliser ailleurs ou utilisez des noms de variables distincts pour chaque boucle.
Il est également capital de souligner l’importance de l’indentation en Python. Telle qu’introduite
dans le chapitre 1, une indentation incorrecte peut provoquer une IndentationError ou altérer
la logique du programme, entraînant des résultats inattendus. Par exemple, une instruction mal
indentée pourrait être exécutée en dehors de la boucle, changeant complètement le comportement
du programme. Vous devez donc vérifier soigneusement l’alignement de chaque ligne dans vos
boucles.
De plus, une indentation incohérente, comme mélanger des espaces et des tabulations, provoque
une TabError. Utilisez toujours 4 espaces par niveau d’indentation, conformément à la norme
PEP 8. Assurez-vous donc toujours que toutes les lignes d’un même bloc ont exactement le même
niveau d’indentation pour éviter des erreurs ou des comportements imprévus.
Dans l’exemple qui suit, la boucle continue tant que compte < 3. À chaque itération, compte est
incrémenté avec += 1. Lorsque compte atteint 3, la condition devient False et la boucle s’arrête.
>>> compte = 0
>>> while compte < 3:
... print(f"Itération {compte}")
... compte += 1
...
Itération 0
Itération 1
Itération 2
On peut également utiliser la boucle while pour contrôler l’entrée utilisateur. Voici un exemple
pour demander une entrée valide :
1 # Demande un nombre positif
2 nombre = float(input("Entrez un nombre strictement positif : "))
3 while nombre <= 0:
4 print("Erreur : le nombre doit être strictement positif.")
5 nombre = float(input("Entrez un nombre strictement positif : "))
6 print(f"Merci, vous avez entré {nombre}.")
La boucle while continue de demander une saisie tant que nombre <= 0. Une fois que nombre > 0,
la boucle s’arrête.
Une boucle while peut devenir infinie si la condition ne devient jamais False. Cela peut survenir si
vous oubliez de modifier une variable dans la boucle ou si la condition est mal définie. Par exemple,
while True: sans mécanisme de sortie (comme break) exécutera le programme indéfiniment, ce
qui peut bloquer votre terminal ou consommer des ressources.
Voici une boucle infinie accidentelle :
>>> n = 3
>>> while n > 0:
... print(n)
... # Oubli de décrémenter n
...
3
3
3
... (continue indéfiniment)
Pour éviter les boucles infinies, vérifiez toujours que la condition de votre boucle while peut
devenir False à un moment donné.
Dès que lettre == "j", break interrompt la boucle et les caractères restants (o, u, r) ne sont pas
vérifiés.
Un autre exemple avec la boucle while :
1 # Boucle avec option de quitter
2 while True:
3 reponse = input("Entrez un mot (ou 'quitter' pour arrêter) : ")
4 if reponse == "quitter":
5 break
6 print(f"Vous avez entré : {reponse}")
7 print("Programme terminé.")
La boucle while True est potentiellement infinie, mais break l’arrête lorsque l’utilisateur entre
quitter.
Lorsque i est pair (i % 2 == 0), continue saute l’instruction print() et seuls les nombres impairs
sont affichés.
Note. Un usage excessif de break et continue peut compliquer la lisibilité du code, car ils
introduisent des sauts dans le flux naturel de la boucle. Une boucle avec de multiples continue peut
être difficile à suivre, car il faut vérifier quelles instructions sont sautées. Préférez des conditions
explicites dans la boucle while ou des séquences filtrées dans une boucle for lorsque possible. Par
exemple, au lieu de continue pour ignorer les nombres pairs, vous pourriez utiliser range(1, 6,
2) pour ne parcourir que les impairs.
• ValueError : Levée lorsqu’une fonction reçoit une valeur inappropriée, comme int("abc").
• TypeError : Levée lorsqu’une opération est appliquée à des types incompatibles, comme
"5" + 3.
• ZeroDivisionError : Levée lors d’une division par zéro, comme 10 / 0.
Les blocs try et except permettent de capturer (catch) ces exceptions pour les traiter sans arrêter
Points clés :
• Le bloc try contient les instructions que vous voulez surveiller pour des erreurs. Si une
exception est levée dans ce bloc, l’exécution s’arrête immédiatement à l’instruction fautive et
Python passe au bloc except correspondant.
• Le bloc except spécifie le type d’exception à capturer (par exemple, ValueError). Si
l’exception levée correspond, le bloc except s’exécute ; sinon, l’exception n’est pas capturée
et peut arrêter le programme.
• L’indentation est essentielle : les instructions sous try et except doivent être correctement
alignées pour indiquer leur appartenance à chaque bloc.
Testons un bloc try−except pour gérer une conversion risquée :
>>> try:
... nombre = int(input("Entrez un entier : "))
... print(f"Vous avez entré : {nombre}")
... except ValueError:
... print("Erreur : veuillez entrer un entier valide.")
...
Entrez un entier : 42
Vous avez entré : 42
Entrez un entier : abc
Erreur : veuillez entrer un entier valide.
Explications :
• Dans le bloc try, int(input(...)) tente de convertir l’entrée en entier.
• Si l’entrée est valide (par exemple, "42"), la conversion réussit et print() affiche le résultat.
• Si l’entrée est invalide (par exemple, "abc"), int() lève une ValueError et le bloc except
ValueError s’exécute, affichant un message d’erreur.
• Saisie abc :
Entrez un entier : abc
Erreur : veuillez entrer un entier valide.
Le programme continue.
• Saisie 0 :
Entrez un entier : 0
Erreur : division par zéro impossible.
Le programme continue.
Explications :
• Le bloc try tente une conversion (int()) et une division (100 / nombre).
• Si int() échoue, ValueError est capturé et un message approprié s’affiche.
• Si nombre est 0, ZeroDivisionError est capturé pour la division.
Note. Capturer toutes les exceptions avec un except générique peut cacher des erreurs graves
ou inattendues, comme une KeyboardInterrupt (lorsque l’utilisateur interrompt le programme
avec Ctrl+C). Privilégiez des blocs except spécifiques pour garder le contrôle sur les erreurs
gérées. De plus, si plusieurs blocs except sont utilisés, placez les exceptions spécifiques avant
un except générique, car Python exécute le premier bloc correspondant. Par exemple, except
ValueError doit précéder except, sinon le except générique capturera tout en rendant ValueError
inaccessible.
Explications :
• Le bloc try protège uniquement les opérations risquées (int() et /), cela limite la portée de
la gestion d’erreurs.
• Les messages d’erreur sont spécifiques et informatifs en guidant l’utilisateur.
Note. À ce stade, try−except est un outil simple mais puissant pour gérer les erreurs courantes,
comme les entrées invalides ou les divisions par zéro. Il remplace les vérifications manuelles par
une approche plus élégante en permettant au programme de "tenter" une opération et de réagir si
elle échoue. Consultez la documentation officielle 1 ou Real Python 2 si vous souhaitez explorer
des fonctionnalités avancées, comme les clauses else et finally, la levée d’exceptions avec
raise et la création d’exceptions personnalisées. Pour l’instant, concentrez-vous sur la capture des
exceptions courantes avec des blocs spécifiques et des messages clairs.
1. [Link]
2. [Link]
Avant ce chapitre, vos programmes ont manipulé des données simples, comme des nombres, des
chaînes ou des booléens, stockés dans des variables individuelles. Cependant, dans de nombreuses
situations, vous devez gérer des ensembles de données organisées, comme une liste de notes, une
série de noms ou une collection de mesures. Les collections en Python permettent de regrouper
plusieurs valeurs dans une seule structure, facilitant leur manipulation et leur traitement. Dans ce
chapitre, nous étudierons les principales collections que sont les listes, les tuples, les dictionnaires
et les ensembles. Chaque type a ses propres caractéristiques, usages et méthodes qui vous offrent
des outils puissants pour structurer et analyser des données.
4.1 Listes
Les listes sont des collections ordonnées, modifiables et capables de contenir des éléments de
différents types (nombres, chaînes ou même d’autres listes). Elles sont idéales pour stocker des
données séquentielles.
Une liste est une collection ordonnée et modifiable d’éléments, délimitée par des crochets [] et
séparée par des virgules. Chaque élément est accessible par un index (position, commençant à 0).
Les listes sont l’une des structures de données les plus utilisées en Python en raison de leur
simplicité.
Pour créer une liste, placez les éléments entre crochets [], séparés par des virgules. Une liste peut
être vide ou contenir des éléments de types variés, comme des entiers, des flottants, des chaînes ou
des booléens.
>>> nombres = [1, 2, 3, 4]
>>> mots = ["chat", "chien", "oiseau"]
>>> mixte = [42, "Python", 3.14, True]
>>> vide = []
>>> print(nombres, mots, mixte, vide)
58 Chapitre 4. Collections de données
Chaque liste est définie par ses éléments. vide est une liste sans éléments, utile comme point
de départ pour accumuler des données. Les éléments de mixte montrent que les listes peuvent
mélanger différents types sans restriction.
[Link] Indexation
Les éléments d’une liste sont accessibles via leur indice (ou index), un entier indiquant leur position.
Les indices commencent à 0 pour le premier élément, 1 pour le second et ainsi de suite. Python
permet également une indexation négative, comme vu avec les chaînes de caractères, où −1 désigne
le dernier élément, −2 l’avant-dernier, etc.
>>> fruits = ["pomme", "banane", "orange"]
>>> print(fruits[0])
pomme
>>> print(fruits[2])
orange
>>> print(fruits[−1])
orange
>>> print(fruits[−2])
banane
Explications :
Vous pouvez également modifier un élément en assignant une nouvelle valeur à un index spécifique,
car les listes sont mutables (ou modifiables), contrairement aux chaînes de caractères qui sont
immuables.
Testons la modification via indexation :
>>> fruits = ["pomme", "banane", "orange"]
>>> fruits[1] = "ananas"
>>> print(fruits)
['pomme', 'ananas', 'orange']
fruits[1] = "ananas" remplace "banane" par "ananas". Cette opération ne change pas la taille
de la liste, seulement l’élément à l’index spécifié.
Note. Accéder à un index inexistant provoque une IndexError. Par exemple, fruits[3] dans une
liste de 3 éléments échoue, car les indices valides sont 0, 1, 2. De même, les indices négatifs
doivent rester dans les limites : fruits[−4] échoue pour une liste de 3 éléments.
>>> fruits = ["pomme", "banane"]
>>> print(fruits[2])
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IndexError: list index out of range
Le découpage permet d’extraire une sous-liste en spécifiant une plage d’indices sous la forme
[debut:fin], où debut est inclus et fin est exclu. Vous pouvez également inclure un pas pour
sauter des éléments : [debut:fin:pas]. Si debut ou fin sont omis, Python utilise les valeurs par
défaut (début de la liste ou fin). On se rend compte que la syntaxe est la même que celle utilisée sur
les chaînes de caractères.
>>> nombres = [0, 1, 2, 3, 4, 5]
>>> print(nombres[1:4])
[1, 2, 3]
>>> print(nombres[:3])
[0, 1, 2]
>>> print(nombres[2:])
[2, 3, 4, 5]
>>> print(nombres[::2])
[0, 2, 4]
>>> print(nombres[::−1])
[5, 4, 3, 2, 1, 0]
Explications :
Le découpage peut également être utilisé pour modifier plusieurs éléments à la fois en assignant
une nouvelle liste à une plage d’indices.
>>> nombres = [0, 1, 2, 3, 4]
>>> nombres[1:3] = [10, 20]
>>> print(nombres)
[0, 10, 20, 3, 4]
>>> nombres[1:3] = [25, 35, 45]
>>> print(nombres)
[0, 25, 35, 45, 3, 4]
nombres[1:3] remplace [1, 2] par [10, 20]. La nouvelle liste n’a pas besoin d’avoir la même
longueur, ce qui peut modifier la taille de la liste.
Note. Le slicing est une fonctionnalité puissante des listes pour extraire ou modifier des sous-
ensembles. Cependant, un découpage mal défini (par exemple, [5:2] sans pas négatif) retourne une
liste vide, car la plage est invalide. Testez vos découpages avec des cas limites pour comprendre
leur comportement.
En plus de la création manuelle avec des crochets, les listes supportent plusieurs opérations
qui permettent de les manipuler de manière efficace : concaténation pour fusionner des listes,
multiplication pour répéter des éléments, conversion d’autres types en listes avec la fonction
list() et calculs statistiques avec des fonctions comme min(), max() et sum().
La concaténation combine deux listes pour en former une nouvelle contenant tous leurs éléments
dans l’ordre. L’opérateur + crée une nouvelle liste, tandis que la méthode extend() modifie une
liste existante en ajoutant les éléments d’une autre.
>>> liste1 = [1, 2, 3]
>>> liste2 = [4, 5]
>>> nouvelle_liste = liste1 + liste2
>>> print(nouvelle_liste)
[1, 2, 3, 4, 5]
>>> print(liste1, liste2)
[1, 2, 3] [4, 5]
L’opérateur + crée nouvelle_liste en combinant liste1 et liste2, sans modifier les originales.
Maintenant, utilisons extend() :
>>> liste1 = [1, 2, 3]
>>> liste2 = [4, 5]
>>> [Link](liste2)
>>> print(liste1)
[1, 2, 3, 4, 5]
>>> print(liste2)
[4, 5]
Multiplication avec *
L’opérateur * répète les éléments d’une liste un nombre spécifié de fois en créant une nouvelle liste.
>>> items = ["stylo", "cahier"]
>>> repete = items * 3
>>> print(repete)
['stylo', 'cahier', 'stylo', 'cahier', 'stylo', 'cahier']
>>> print(items)
['stylo', 'cahier']
items * 3 crée une nouvelle liste avec les éléments de items répétés trois fois. La liste originale
items reste inchangée.
Vous pouvez également utiliser * pour initialiser une liste avec des valeurs répétées, comme une
liste de zéros.
>>> zeros = [0] * 5
>>> print(zeros)
[0, 0, 0, 0, 0]
[0] * 5 crée une liste de 5 zéros, utile pour initialiser des compteurs ou des tableaux.
Note. L’opérateur * crée une nouvelle liste, donc liste * 2 ne modifie pas liste à moins de
réassigner le résultat. De plus, multiplier par un entier négatif ou zéro produit une liste vide ([]).
Par exemple, [1, 2] * 0 donne [].
Fonction list()
La fonction list() convertit un objet itérable (comme une chaîne, un tuple ou un objet range) en
une liste. Elle est particulièrement utile pour transformer des séquences générées, comme celles
produites par range(), en listes manipulables.
>>> liste_nombres = list(range(5))
>>> print(liste_nombres)
[0, 1, 2, 3, 4]
>>> texte = "abc"
>>> liste_caracteres = list(texte)
>>> print(liste_caracteres)
['a', 'b', 'c']
Note. La fonction list() est essentielle pour travailler avec range(), car un objet range n’est
pas une liste et ne supporte pas directement l’indexation ou les méthodes de liste. Par exemple,
range(5)[0] provoque une erreur, mais list(range(5))[0] retourne 0. Il faut également retenir
que la fonction list() ne s’applique qu’aux objets séquentiels, i.e. aux collections ordonnées
d’éléments comme les chaînes de caractères, les tuples (qu’on abordera dans la section suivante),
les ranges, etc.
Note. Les fonctions min() et max() nécessitent que les éléments soient comparables. Une liste
mixte (par exemple, [1, "deux"]) provoque une TypeError, car Python ne peut pas comparer
un entier et une chaîne. sum() ne fonctionne que sur des listes de nombres (entiers ou flottants) ;
l’utiliser sur des chaînes ou des booléens échoue. De plus, appliquer min(), max() ou sum() à une
liste vide provoque une ValueError (pour min() et max()) ou retourne 0 (pour sum()).
>>> min([1, "deux"])
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: '<' not supported between instances of 'str' and 'int'
>>> max([])
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: max() iterable argument is empty
>>> sum([])
0
Une méthode de liste est une fonction associée à un objet liste, invoquée avec la syntaxe liste.
methode(arguments). Les méthodes modifient souvent la liste directement (in-place) ou renvoient
une information à son sujet.
Voici les méthodes principales :
• append(element) : Ajoute un élément à la fin de la liste.
• insert(index, element) : Ajoute un élément à un indice spécifique de la liste.
• pop(index) : Supprime et retourne l’élément à l’index spécifié (ou le dernier si aucun index
n’est donné).
• sort() : Trie la liste en place, par ordre croissant.
• reverse() : Inverse l’ordre des éléments en place.
• len(liste) : Retourne le nombre d’éléments (fonction intégrée, pas une méthode).
• count(element) : Compte les occurrences d’un élément.
• clear() : Supprime tous les éléments, laissant une liste vide.
append("œufs") ajoute "œufs" à la fin. La liste est modifiée directement, sans besoin de réassi-
gnation.
pop() sans argument supprime "orange" et pop(0) supprime "pomme". La liste est modifiée et les
éléments supprimés sont retournés.
Note. Appeler pop() sur une liste vide ou avec un index invalide provoque une IndexError. Par
exemple, [].pop() ou [Link](5) pour une liste de 3 éléments échoue.
La méthode sort() trie la liste en place, par défaut, par ordre croissant pour les nombres ou
lexicographique pour les chaînes. Mais un argument reverse permet de contrôler l’ordre (True
pour décroissant). La méthode reverse() inverse l’ordre des éléments, sans nécessairement trier.
>>> nombres = [3, 1, 4, 2]
>>> [Link]()
>>> print(nombres)
[1, 2, 3, 4]
>>> [Link](reverse=True)
>>> print(nombres)
[4, 3, 2, 1]
>>> mots = ["chat", "âne", "bœuf"]
>>> [Link]()
>>> print(mots)
['bœuf', 'chat', 'âne']
>>> [Link]()
>>> print(mots)
['âne', 'chat', 'bœuf']
sort() organise nombres en ordre croissant et mots en ordre lexicographique (Unicode). Lorsque
l’argument reverse=True, le tri se fait par ordre décroissant. reverse() inverse l’ordre actuel,
indépendamment du tri.
Note. sort() ne fonctionne que sur des listes homogènes (par exemple, nombres uniquement ou
chaînes uniquement). Trier une liste mixte (comme [1, "deux", 3]) provoque une TypeError, car
Python ne peut pas comparer des types différents. Assurez-vous que les éléments sont comparables
avant d’appeler sort().
La fonction len() retourne la longueur de la liste. count() compte combien de fois un élément
apparaît. clear() vide la liste, la laissant avec zéro élément.
>>> notes = [10, 15, 10, 12]
>>> print(len(notes))
4
>>> print([Link](10))
2
>>> [Link]()
>>> print(notes)
[]
len(notes) donne 4, count(10) indique que 10 apparaît deux fois et clear() supprime tous les
éléments.
Une liste imbriquée est une liste contenant une ou plusieurs listes comme éléments. Cela crée une
structure hiérarchique, comme une matrice ou un tableau à deux dimensions, utile pour représenter
des données complexes, comme des coordonnées ou des tables de valeurs.
>>> matrice = [[1, 2], [3, 4], [5, 6]]
>>> print(matrice)
[[1, 2], [3, 4], [5, 6]]
>>> print(matrice[1])
[3, 4]
>>> print(matrice[1][0])
3
Explications :
• matrice contient trois sous-listes : [1, 2], [3, 4], [5, 6].
• matrice[1] accède à la deuxième sous-liste, [3, 4].
• matrice[1][0] accède au premier élément de la deuxième sous-liste, 3.
Les listes imbriquées peuvent être modifiées comme des listes simples, en utilisant l’indexation
pour accéder aux sous-listes et à leurs éléments.
>>> grille = [[0, 0], [0, 0]]
>>> grille[0][1] = 1
>>> print(grille)
[[0, 1], [0, 0]]
Copier une liste peut sembler simple, mais une assignation directe (par exemple, liste2 = liste1)
ne crée pas une nouvelle liste : elle crée une référence à la même liste. Modifier liste2 affecte
alors liste1, ce qui peut entraîner des erreurs logiques.
Observons le problème de la référence :
>>> liste1 = [1, 2, 3]
>>> liste2 = liste1
>>> liste2[0] = 99
>>> print(liste1, liste2)
[99, 2, 3] [99, 2, 3]
liste2 = liste1 fait que liste2 pointe vers la même liste. Modifier liste2 change liste1.
Pour créer une copie indépendante, utilisez la méthode copy() ou le découpage [:]. Voici une
copie correcte :
copy() crée une nouvelle liste et modifier liste2 n’affecte pas liste1. Le découpage liste2 =
liste1[:] produit le même résultat.
Note. La méthode copy() et le découpage [:] créent une copie superficielle (shallow copy) qui ne
copie que la liste extérieure. Si la liste contient des sous-listes (imbriquées), les sous-listes restent
des références. Modifier une sous-liste dans la copie affecte l’originale. Par exemple :
>>> original = [[1, 2], [3, 4]]
>>> copie = [Link]()
>>> copie[0][0] = 99
>>> print(original, copie)
[[99, 2], [3, 4]] [[99, 2], [3, 4]]
Pour copier des listes imbriquées, une copie profonde (deep copy) est nécessaire utilisant le module
copy qui sera abordé dans la section [Link] du chapitre 6. Pour l’instant, soyez prudents avec les
listes imbriquées lors de la copie.
Dans cet exemple, la variable nom prend successivement la valeur de chaque élément de la liste
noms ("Alice", "Bob", puis "Charlie").
Note. Lorsque vous parcourez une liste directement avec for element in liste, vous accédez
uniquement aux éléments, pas à leurs indices. Si vous avez besoin des indices, vous devrez utiliser
une méthode différente, comme la fonction enumerate() déjà étudiée dans le chapitre des structures
de contrôle.
Pour rappel, la fonction enumerate() permet de parcourir simultanément les indices et les éléments
d’une liste. Elle renvoie des paires (indice, élément) à chaque itération.
Affichons les éléments d’une liste avec leur position :
Note. Par défaut, enumerate() commence à compter les indices à partir de 0. Vous pouvez modifier
ce comportement en spécifiant un indice de départ avec l’argument start. Par exemple :
>>> fruits = ["pomme", "banane", "orange"]
>>> for indice, fruit in enumerate(fruits, start=1):
... print(f"Fruit {indice} : {fruit}")
...
Fruit 1 : pomme
Fruit 2 : banane
Fruit 3 : orange
Bien que le parcours direct ou avec enumerate() soit généralement préférable, il est également
possible de parcourir une liste en utilisant les indices avec la fonction range() et la fonction len().
Cette approche est moins courante mais peut être utile dans certains cas, notamment si vous devez
modifier la liste pendant le parcours.
Affichons les éléments d’une liste en utilisant les indices :
>>> couleurs = ["rouge", "vert", "bleu"]
>>> for i in range(len(couleurs)):
... print(f"Couleur à l'indice {i} : {couleurs[i]}")
...
Couleur à l'indice 0 : rouge
Couleur à l'indice 1 : vert
Couleur à l'indice 2 : bleu
4.2 Tuples
Les tuples constituent une autre structure de données fondamentale en Python, utilisée pour stocker
une collection ordonnée d’éléments. Contrairement aux listes étudiées dans la section précédente,
les tuples sont immuables, c’est-à-dire que leur contenu ne peut pas être modifié après leur création.
Cette propriété d’immuabilité confère aux tuples des avantages spécifiques, notamment en termes
de performance et de sécurité dans certains contextes. Vous découvrirez dans cette section comment
créer, manipuler et utiliser les tuples, ainsi que leurs cas d’usage typiques.
Un tuple est une collection ordonnée et immuable d’éléments qui peuvent être de types différents
(nombres, chaînes, autres tuples, etc.). Les tuples sont généralement délimités par des parenthèses
() et les éléments sont séparés par des virgules.
Quelques points importants concernant la syntaxe des tuples doivent être notés :
• Un tuple vide est créé avec des parenthèses vides : mon_tuple = () ou avec la fonction
tuple() : mon_tuple = tuple().
• Un tuple avec un seul élément nécessite une virgule finale pour éviter d’être interprété comme
une simple expression entre parenthèses. Par exemple :
>>> tuple_un_element = (5,) # Tuple avec un seul élément
>>> pas_un_tuple = (5) # Juste un entier, pas un tuple
>>> type(tuple_un_element)
<class 'tuple'>
>>> type(pas_un_tuple)
<class 'int'>
• Les parenthèses sont souvent facultatives, sauf pour clarifier la syntaxe ou pour un tuple vide.
Ainsi, a = 1, 2, 'a' crée un tuple implicite (1, 2, 'a').
Note. Omettre la virgule finale pour un tuple à un seul élément est une erreur courante. Assurez-
vous de toujours inclure la virgule, comme dans (5,), pour que Python reconnaisse correctement
le tuple.
Cet exemple montre que tenter de modifier un élément d’un tuple provoque une erreur TypeError.
Cette immutabilité fait des tuples un choix idéal pour représenter des données qui ne doivent pas
changer, comme les coordonnées d’un point dans l’espace ou les jours de la semaine.
Note. Bien que les tuples soient immuables, ils peuvent contenir des objets mutables, comme
des listes. Dans ce cas, le contenu de ces objets peut être modifié, mais la structure du tuple (les
références aux objets) reste fixe. Par exemple :
>>> tuple_avec_liste = ([1, 2], "fixe")
>>> tuple_avec_liste[0][0] = 99
>>> print(tuple_avec_liste)
([99, 2], 'fixe')
Le déballage est également utilisé dans des contextes comme l’échange de variables sans variable
temporaire :
>>> a = 10
>>> b = 20
>>> a, b = b, a # Échange des valeurs via un tuple implicite
>>> print(a, b)
20 10
Note. Le nombre de variables à gauche du signe = doit correspondre au nombre d’éléments dans le
tuple, sinon une erreur ValueError est levée. Par exemple :
>>> x, y = (1, 2, 3) # Trop d'éléments
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: too many values to unpack (expected 2)
Si certains éléments ne vous intéressent pas, vous pouvez utiliser l’underscore (_) pour les ignorer :
>>> x, _, z = (1, 2, 3)
>>> print(x, z)
1 3
Cela permet de ne pas créer de variables inutiles pour des éléments que l’on souhaite simplement
ignorer.
Cet exemple illustre comment le déballage facilite l’accès aux informations stockées dans le tuple.
Note. Choisir entre une liste et un tuple dépend du contexte. Si les données doivent rester constantes,
optez pour un tuple. Si elles doivent être modifiées, une liste est plus appropriée.
4.3 Dictionnaires
Les dictionnaires sont une structure de données puissante en Python qui permet de stocker des
données sous forme de paires clé-valeur. Contrairement aux listes et aux tuples qui utilisent des
indices numériques pour accéder aux éléments, les dictionnaires associent chaque valeur à une clé
unique, ce qui facilite la recherche et la manipulation de données.
Un dictionnaire est une collection ordonnée (depuis Python 3.7) 1 , mutable et non indexée numéri-
quement, qui stocke des paires clé-valeur. Les clés doivent être immuables (comme des chaînes,
des nombres ou des tuples) et uniques, tandis que les valeurs peuvent être de n’importe quel type.
Les dictionnaires sont délimités par des accolades {} et les paires sont séparées par des virgules.
• Les clés peuvent être de types immuables comme str, int, float ou tuple, mais pas de
1. Jusqu’à la version 3.6 de Python, un dictionnaire était affiché sans ordre particulier. C’était une collection non
ordonnée, c’est-à-dire que l’ordre d’affichage des éléments n’était pas forcément le même que celui dans lequel il avait
été rempli. Pour plus de détails, consultez : [Link]
iscovering-dictionary-order-in-python.
Pour éviter cette erreur, la méthode get() est une alternative sûre, renvoyant None (ou une valeur
par défaut spécifiée) si la clé n’existe pas :
>>> print([Link]("pays")) # Renvoie None
None
>>> print([Link]("pays", "Bénin")) # Renvoie "Bénin" par défaut
Bénin
Note. Utiliser dict[clé] pour accéder à une valeur est rapide mais risque une KeyError. Préférez
[Link](clé) pour un accès sécurisé, surtout lorsque la présence de la clé n’est pas garantie.
Pour ajouter une nouvelle paire, assignez une valeur à une clé inexistante :
>>> personne["ville"] = "Bohicon"
>>> print(personne)
{'nom': 'Alice', 'age': 26, 'ville': 'Bohicon'}
Note. L’utilisation de pop(clé) ou del avec une clé inexistante provoque une KeyError. Pour
pop(), vous pouvez spécifier une valeur par défaut : mon_dict.pop("clé", None).
Les mentions dict_keys, dict_values et dict_items indiquent que nous avons à faire à des
objets un peu particuliers. Ils ne sont pas indexables (on ne peut pas retrouver un élément par indice,
par exemple mon_dict.keys()[0] renverra une erreur). Si besoin, nous pouvons les transformer
en liste avec la fonction list() :
>>> mon_dict = {"a": 1, "b": 2, "c": 3}
>>> list(mon_dict.keys())
['a', 'b', 'c']
Toutefois, ces trois objets sont itérables : on peut itérer dessus dans une boucle.
Considérons un dictionnaire de scores :
1 scores = {"Alice": 90, "Bob": 85, "Charlie": 88}
2 # Parcourir les clés
3 for nom in [Link]():
4 print(f"Clé : {nom}")
5 # Parcourir les valeurs
6 for score in [Link]():
7 print(f"Score : {score}")
8 # Parcourir les paires
9 for nom, score in [Link]():
10 print(f"{nom} a obtenu {score}")
Note. Parcourir directement un dictionnaire avec for clé in dict est équivalent à for clé in
[Link](). Cependant, utiliser keys() explicitement améliore la lisibilité du code.
Note. Choisir entre une liste, un tuple ou un dictionnaire dépend du problème. Utilisez un
dictionnaire lorsque vous devez associer des clés à des valeurs pour un accès rapide.
4.4 Ensembles
Les ensembles, ou sets en Python, sont une structure de données conçue pour stocker une collection
d’éléments uniques, sans ordre défini. Inspirés des ensembles mathématiques, ils sont particu-
lièrement utiles pour effectuer des opérations ensemblistes comme l’union, l’intersection ou la
différence, ainsi que pour éliminer les doublons dans une collection.
Un ensemble est une collection non ordonnée, mutable et ne contenant que des éléments uniques et
immuables (comme des nombres, des chaînes ou des tuples). Les ensembles sont délimités par des
accolades {} et ne permettent pas de doublons.
• Les sets ne sont pas indexables, il est donc impossible de récupérer un élément par sa position.
Il est également impossible de modifier un de ses éléments par l’indexation.
>>> mon_ensemble = {1, 2, 3, 2}
>>> mon_ensemble[0]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'set' object is not subscriptable
>>> mon_ensemble[0] = 0
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'set' object does not support item assignment
Note. Confondre {} pour un ensemble vide avec un dictionnaire vide est une erreur courante.
Utilisez toujours set() pour créer un ensemble vide.
Note. La méthode pop() renvoie un élément arbitraire, car les ensembles ne garantissent pas un
ordre spécifique. Utilisez-la avec prudence.
Note. [Link](b) retourne un nouvel ensemble avec des éléments présents dans a mais pas
dans b. Ainsi, [Link](b) != [Link](a). Cependant, a.symmetric_difference(
b) == b.symmetric_difference(a).
Note.
Il existe d’autres méthodes que nous n’abordons pas ici, mais qui peuvent être consultées sur la
documentation officielle de Python 2 ou en tapant help(set) dans le shell.
Note. Les frozensets supportent les mêmes opérations ensemblistes que les sets, mais aucune
méthode de modification comme add(), remove() ou discard(), puisqu’ils sont non modifiables.
Les frozensets peuvent également être convertis en liste ou en tuple, à l’instar des sets.
2. [Link]
La fonction zip() combine plusieurs itérables (comme des listes, tuples ou ensembles) en un
itérateur de tuples, où chaque tuple contient les éléments correspondants des itérables d’entrée.
Cette fonction permet ainsi de parcourir plusieurs collections en parallèle.
Dans cet exemple, zip(noms, scores) crée un itérateur de tuples ('Alice', 90), ('Bob', 85),
etc. La conversion en liste avec list() permet d’afficher le résultat.
On peut directement parcourir les paires créées sans les convertir en une liste :
>>> for nom, score in zip(noms, scores):
... print(f"{nom} a {score} points.")
...
Alice a 90 points.
Bob a 85 points.
Charlie a 88 points.
Ici, zip() permet de déballer chaque tuple directement dans la boucle for.
Note. Si les itérables passés à zip() ont des longueurs différentes, les éléments excédentaires du
plus long itérable sont ignorés. Par exemple :
>>> noms = ["Alice", "Bob", "Charlie"]
>>> scores = [90, 85, 88]
>>> ages = [25, 30]
>>> print(list(zip(noms, ages, scores)))
[('Alice', 25, 90), ('Bob', 30, 85)]
La fonction map() applique une fonction à chaque élément d’un itérable en renvoyant un itérateur
des résultats. Elle est utile pour transformer des collections sans écrire de boucle explicite.
Ici, la fonction intégrée abs (qui calcule la valeur absolue d’un nombre) est appliquée à chaque
élément de nombres et list() convertit l’itérateur en liste.
Note. Les fonctions zip() et map() (ainsi qu’enumerate()) renvoient des itérateurs qui sont
évalués paresseusement (lazily). Cela veut dire qu’ils ne calculent pas tout d’un coup ; ils produisent
les résultats au fur et à mesure quand on les demande. Pour faire court, c’est lorsqu’on parcourt
l’itérateur que Python calcule. Cela permet d’économiser la mémoire et le temps pour de grandes
collections. Pour calculer tous les éléments, convertissez les itérateurs en liste. Mais rappelez-vous
que cela consomme de la mémoire.
Une compréhension de liste crée une nouvelle liste en appliquant une expression à chaque élément
d’un itérable, éventuellement avec une condition.
La syntaxe la plus simple est :
3. [Link]
Pour chaque élément de l’itérable, l’expression est appliquée si la condition (facultative) est
vérifiée. Tous les résultats sont alors regroupés immédiatement dans une nouvelle liste.
Pour créer une liste des carrés des nombres de 1 à 5 :
>>> carres = [x**2 for x in range(1, 6)]
>>> print(carres)
[1, 4, 9, 16, 25]
• Lorsque if est utilisé seul (sans else), il se place après la boucle for.
• Lorsque if−else sont utilisés ensemble, ils doivent apparaître avant la boucle for.
Supposons que l’on veuille créer une liste des caractères de 'ananas' en remplaçant les consonnes
par '*'.
>>> voyelles = [x for x in 'ananas' if x in 'aeiou' else '*']
File "<stdin>", line 1
voyelles = [x for x in 'ananas' if x in 'aeiou' else '*']
^^^^
SyntaxError: invalid syntax
Nous avons une SyntaxError. Python ne comprend pas où placer else car if appliqué après le
for est censé être une simple condition de filtrage, sans clause alternative. La bonne syntaxe est
alors :
1 >>> voyelles = [x if x in 'aeiou' else '*' for x in 'ananas']
2 >>> print(voyelles)
3 ['a', '*', 'a', '*', 'a', '*']
Pour chaque caractère x dans 'ananas' ; si x est une voyelle, on garde x ; sinon, on met '*'.
Note. Les compréhensions de listes sont puissantes, mais une utilisation excessive peut rendre le
code difficile à lire. Préférez une boucle for explicite si la compréhension devient trop complexe
ou imbriquée.
Une compréhension de dictionnaire crée un dictionnaire en spécifiant des paires clé-valeur à partir
d’un itérable.
Pour créer un dictionnaire associant des nombres à leurs carrés :
>>> carres_dict = {x: x**2 for x in range(1, 5)}
>>> print(carres_dict)
{1: 1, 2: 4, 3: 9, 4: 16}
Comme avec une compréhension de liste, nous pouvons utiliser une instruction conditionnelle (if
/if−else) à l’intérieur de la compréhension de dictionnaire pour produire uniquement les éléments
du dictionnaire répondant à certains critères.
>>> notes = {"Alice": 90, "Bob": 85, "Charlie": 88}
>>> fortes_notes = {nom: score for nom, score in [Link]() if score >= 88}
>>> print(fortes_notes)
{'Alice': 90, 'Charlie': 88}
Une compréhension d’ensemble crée un ensemble en appliquant une expression à un itérable tout
en éliminant automatiquement les doublons.
Pour créer un ensemble des longueurs uniques de mots :
>>> mots = ["bonjour", "python", "code", "bon", "oui"]
>>> longueurs = {len(mot) for mot in mots}
>>> print(longueurs)
{3, 4, 6, 7}
Gardez à l’esprit que les ensembles ne sont pas ordonnés. Cela signifie que l’ordre des résultats
dans l’ensemble peut différer de celui présenté dans les exemples ci-dessus.
Notes.
1. Il est également possible d’utiliser une instruction conditionnelle (if/if−else) à l’intérieur
de la compréhension d’ensemble.
2. Il n’existe pas de compréhension pour les tuples, car les tuples sont immuables.
3. Le choix entre boucles et compréhensions dépend de la lisibilité et de la complexité de la
tâche. Pour les débutants, les boucles explicites sont souvent plus simples à utiliser, tandis
que les compréhensions deviennent naturelles avec la pratique.
Le corps de la fonction est indenté sous la ligne de définition (l’indentation est obligatoire). Le
mot-clé return est utilisé pour renvoyer un résultat, bien qu’il soit facultatif si la fonction ne
produit pas de valeur. Une fois définie, une fonction peut être appelée en utilisant son nom suivi
d’arguments et exécute une tâche spécifique. L’appel d’une fonction consiste à invoquer son nom
avec des arguments : nom_de_la_fonction(arguments).
82 Chapitre 5. Fonctions
La fonction nommée carre prend un paramètre nombre, calcule son carré et renvoie le résultat
avec return. Les arguments fournis lors de l’appel remplacent les paramètres dans le corps de la
fonction. C’est ce qui a été fait à la ligne 5 : l’appel carre(5) passe l’argument 5 au paramètre
nombre. La fonction calcule 5 ** 2 et renvoie 25 qui est stocké dans resultat.
Notez qu’une fonction peut être appelée plusieurs fois avec différents arguments (ce qui constitue
l’intérêt même de leur utilisation) :
1 print(carre(3))
2 print(carre(10))
Notez également qu’une fonction ne prend pas forcément un argument et ne renvoie pas forcément
une valeur, par exemple :
1 def saluer():
2 print("Bonjour !")
3
4 saluer()
Bonjour !
Dans ce cas, la fonction hello() se contente d’afficher la chaîne de caractères "Bonjour !" à
l’écran. Elle ne prend aucun argument et ne renvoie rien. Par conséquent, cela n’a pas de sens de
vouloir récupérer dans une variable le résultat renvoyé par une telle fonction. Si on essaie tout de
même, Python affecte la valeur None qui signifie rien en anglais :
1 def saluer():
2 print("Bonjour !")
3
4 resultat = saluer()
5 print(resultat)
Bonjour !
None
Note. Le nom d’une fonction doit être descriptif et suivre les conventions de nommage de Python
(PEP 8). Évitez les noms réservés comme print ou len, car cela peut écraser les fonctions intégrées.
5.2 Paramètres
Les paramètres d’une fonction permettent de transmettre des données spécifiques lors de son appel.
Python offre plusieurs façons de définir et d’utiliser les paramètres, y compris les paramètres
positionnels, les paramètres par mot-clé, les valeurs par défaut et les paramètres variables.
• Paramètres positionnels : Les arguments sont passés dans l’ordre exact des paramètres
définis dans la fonction, chaque argument correspondant au paramètre à la même position.
• Paramètres par mot-clé : Les arguments sont passés en spécifiant explicitement le nom du
paramètre, ce qui permet de les passer dans n’importe quel ordre.
• Valeurs par défaut : Un paramètre peut avoir une valeur prédéfinie utilisée si aucun argument
correspondant n’est fourni lors de l’appel.
Les paramètres positionnels sont le moyen le plus courant de passer des arguments à une fonction.
Lors de l’appel, les arguments doivent être fournis dans le même ordre que les paramètres définis
dans la déclaration de la fonction.
Considérons une fonction qui affiche les informations d’un étudiant :
>>> def afficher_etudiant(nom, age, cours):
... print(f"{nom} a {age} ans et suit le cours {cours}.")
...
Pour appeler cette fonction, les arguments doivent être passés dans l’ordre nom, age, cours :
>>> afficher_etudiant("Alice", 20, "Programmation Python")
Alice a 20 ans et suit le cours Programmation Python.
Dans cet exemple, "Alice" est assigné à nom, 20 à age et "Programmation Python" à cours en
suivant l’ordre des paramètres.
Si les arguments sont passés dans un ordre incorrect, le résultat peut être incohérent ou provoquer
une erreur logique :
>>> afficher_etudiant(20, "Alice", "Programmation Python")
20 a Alice ans et suit le cours Programmation Python.
Note. L’ordre des arguments positionnels est très important. Une erreur dans l’ordre peut entraîner
des résultats inattendus ou des erreurs si les types des arguments ne correspondent pas aux attentes
de la fonction. Par exemple, passer une chaîne là où un nombre est attendu peut provoquer une
TypeError dans certaines opérations.
Les paramètres par mot-clé permettent de passer des arguments en spécifiant explicitement le nom
du paramètre, ce qui élimine la nécessité de respecter l’ordre des paramètres. Les arguments par
mot-clé améliorent la lisibilité, surtout pour les fonctions avec plusieurs paramètres.
Reprenons la fonction afficher_etudiant :
>>> afficher_etudiant(age=20, nom="Alice", cours="Programmation Python")
Alice a 20 ans et suit le cours Programmation Python.
Ici, les arguments sont passés en utilisant les noms des paramètres et l’ordre n’a pas d’importance. Le
résultat est identique à l’appel positionnel afficher_etudiant("Alice", 20, "Informatique
").
Les paramètres par mot-clé peuvent être combinés avec des paramètres positionnels, mais les
arguments positionnels doivent toujours être fournis en premier :
>>> afficher_etudiant("Alice", age=20, cours="Programmation Python")
Alice a 20 ans et suit le cours Programmation Python.
Notes.
1. Si un argument positionnel est fourni après un argument par mot-clé dans le même appel,
Python lève une SyntaxError. Par exemple :
>>> afficher_etudiant(nom="Alice", 20, "Programmation Python")
File "<stdin>", line 1
afficher_etudiant(nom="Alice", 20, "Programmation Python")
^
SyntaxError: positional argument follows keyword argument
2. L’utilisation des paramètres par mot-clé est utile pour les fonctions avec de nombreux
paramètres ou lorsque certains paramètres ont des valeurs par défaut, car elle clarifie l’inten-
tion du code. Par exemple, calculer_prix(prix=100, taxe=0.10) est plus explicite que
calculer_prix(100, 0.10).
Les paramètres avec des valeurs par défaut permettent de rendre certains arguments optionnels.
Si un argument correspondant à un paramètre avec une valeur par défaut n’est pas fourni lors de
l’appel, la valeur par défaut est utilisée.
Définissons une fonction pour calculer le coût d’un billet avec une réduction par défaut :
>>> def calculer_billet(prix_base, reduction=0.1):
... prix_final = prix_base * (1 − reduction)
... return prix_final
...
>>> print(calculer_billet(100))
90.0
>>> print(calculer_billet(100, 0.2))
80.0
Dans le premier appel, reduction prend la valeur par défaut 0.1. Dans le second, 0.2 est utilisé.
Les paramètres avec des valeurs par défaut doivent être placés après les paramètres sans valeur par
défaut dans la définition de la fonction, pour éviter des ambiguïtés lors de l’appel.
Une fonction avec plusieurs paramètres par défaut :
>>> def organiser_evenement(nom, date, lieu="Abomey", heure="18:00"):
... print(f"{nom} aura lieu le {date} à {lieu} à {heure}.")
...
>>> organiser_evenement("Conférence", "01/06/2025")
Conférence aura lieu le 01/06/2025 à Abomey à 18:00.
>>> organiser_evenement("Atelier", "01/07/2025", lieu="Cotonou", heure
="09:30")
Atelier aura lieu le 01/07/2025 à Cotonou à 09:30.
Note. Les valeurs par défaut sont évaluées une seule fois, lors de la définition de la fonction et non
à chaque appel. Cela peut entraîner des comportements inattendus avec des objets mutables comme
les listes. Par exemple :
>>> def ajouter_element(element, liste=[]):
... [Link](element)
... return liste
...
>>> print(ajouter_element(1))
[1]
>>> print(ajouter_element(2))
[1, 2]
La liste par défaut [] est partagée entre les appels, car elle est créée une seule fois. Pour éviter ce
problème, utilisez None comme valeur par défaut et initialisez la liste dans la fonction :
>>> def ajouter_element(element, liste=None):
... if liste is None:
... liste = []
... [Link](element)
... return liste
...
>>> print(ajouter_element(1))
[1]
>>> print(ajouter_element(2))
[2]
• *args : Un paramètre spécial qui collecte tous les arguments positionnels supplémentaires
passés à une fonction dans un tuple. Le nom args est une convention, mais l’astérisque * est
obligatoire.
• **kwargs : Un paramètre spécial qui collecte tous les arguments par mot-clé supplémentaires
passés à une fonction dans un dictionnaire. Le nom kwargs (pour keyword arguments) est
une convention, mais les deux astérisques ** sont obligatoires.
Le paramètre *args permet à une fonction d’accepter un nombre arbitraire d’arguments positionnels
qui sont regroupés dans un tuple à l’intérieur de la fonction. *args est utile pour des fonctions qui
doivent traiter des collections de données de taille variable, comme des sommes, des concaténations
ou des affichages multiples.
Définissons une fonction qui calcule le produit de plusieurs nombres :
>>> def produit(*nombres):
... resultat = 1
... for nombre in nombres:
Dans cet exemple, *nombres collecte tous les arguments positionnels dans un tuple. Par exemple,
l’appel produit(2, 3, 4) fait que nombres vaut (2, 3, 4). La boucle for multiplie chaque
élément pour calculer le produit. Si aucun argument n’est passé, le tuple est vide et la fonction
renvoie 1 (la valeur initiale de resultat).
Notes.
1. Le tuple créé par *args est immuable à l’intérieur de la fonction. Si vous devez modifier les
arguments, convertissez le tuple en liste, mais soyez prudents, car cela peut compliquer la
logique de la fonction.
2. Bien que args soit une convention, vous pouvez utiliser un autre nom, comme dans l’exemple
précédent. Cependant, *args est largement adopté dans la communauté Python pour sa clarté
et sa reconnaissance immédiate.
Le paramètre **kwargs permet à une fonction d’accepter un nombre arbitraire d’arguments par
mot-clé qui sont regroupés dans un dictionnaire où les clés sont les noms des arguments et les
valeurs sont leurs valeurs associées. **kwargs est idéal pour des fonctions qui doivent gérer des
options ou des attributs variés, comme la configuration d’un objet ou l’affichage d’informations
structurées.
Définissons une fonction qui affiche les attributs d’un produit :
>>> def afficher_produit(**attributs):
... for cle, valeur in [Link]():
... print(f"{cle} : {valeur}")
...
>>> afficher_produit(nom="Livre", prix=7000, categorie="Littérature")
nom : Livre
prix : 7000
categorie : Littérature
>>> afficher_produit(marque="Samsung", modele="Galaxy S25", couleur="Noir")
marque : Samsung
modele : Galaxy S25
couleur : Noir
Dans cet exemple, **attributs collecte les arguments par mot-clé dans un dictionnaire. Par
exemple, l’appel afficher_produit(nom="Livre", prix=7000, categorie="Littérature")
crée le dictionnaire {"nom": "Livre", "prix": 7000, "categorie": "Littérature"} que la
fonction parcourt pour afficher chaque paire clé-valeur.
Notes.
1. Les clés des arguments passés à **kwargs doivent être des chaînes valides pour des noms de
variables Python (pas d’espaces, pas de caractères spéciaux). Par exemple, **kwargs ne peut
pas accepter nom complet="John Doe" directement.
2. Comme pour *args, le nom kwargs est une convention. Vous pouvez utiliser un autre nom,
mais **kwargs est recommandé pour maintenir la cohérence avec les pratiques standards.
Les paramètres *args et **kwargs peuvent être utilisés ensemble dans une même fonction, souvent
en combinaison avec des paramètres positionnels ou par mot-clé standards. Lors de la définition
d’une fonction, l’ordre des paramètres doit être respecté : paramètres positionnels obligatoires,
*args, paramètres avec valeurs par défaut puis **kwargs. Cette structure permet de couvrir une
grande variété de scénarios d’appel.
Une fonction qui combine tous les types de paramètres :
>>> def commande_client(client, produit, *extras, remise=0.0, **details):
... print(f"Client : {client}, Produit : {produit}")
... print(f"Extras : {extras}")
... print(f"Remise : {remise:.2%}")
... print("Détails supplémentaires :")
... for cle, valeur in [Link]():
... print(f" {cle} : {valeur}")
...
>>> commande_client("Alice", "Livre", "Cahier", "Stylo", remise=0.1, categorie
="Papeterie", stock=50)
Client : Alice, Produit : Livre
Extras : ('Cahier', 'Stylo')
Remise : 10.00%
Détails supplémentaires :
categorie : Papeterie
stock : 50
Une valeur de retour est le résultat produit par une fonction, transmis à l’appelant via le mot-clé
return. Une fonction peut renvoyer une seule valeur, plusieurs valeurs (sous forme de tuple) ou
aucune valeur (implicitement None). Rappelons la syntaxe générale déjà vue dans la section 5.1 :
1 def nom_fonction(paramètres):
2 # Instructions
Dans cet exemple, la fonction moyenne calcule (10 + 20) / 2 et renvoie 15.0 qui est stocké dans
la variable moy.
Une fonction peut contenir plusieurs instructions return pour gérer différents cas :
>>> def maximum(a, b):
... if a > b:
... return a
... return b
...
>>> print(maximum(5, 3))
5
>>> print(maximum(2, 7))
7
Ici, la fonction maximum renvoie a si a > b, sinon elle renvoie b. Dès qu’une instruction return est
exécutée, la fonction s’arrête.
Note. Tout code placé après une instruction return dans une fonction, appelé code mort, ne sera
jamais exécuté, car return termine immédiatement l’exécution de la fonction. Dans l’exemple
suivant, la ligne 3 ne sera jamais exécutée.
1 def erreur():
2 return 42
3 print("Ce message ne sera jamais affiché")
...
>>> temp = celsius_vers_fahrenheit(25)
>>> print(f"25°C équivaut à {temp}°F")
25°C équivaut à 77.0°F
La fonction renvoie un nombre à virgule flottante qui est stocké dans temp et utilisé dans l’affichage.
Note. Le nombre de variables utilisées pour déballer un tuple retourné doit correspondre exactement
au nombre de valeurs dans le tuple, sinon une ValueError est levée. Par exemple :
>>> a, b, c = ajuster_rectangle(10, 5) # Trop de variables
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: not enough values to unpack (expected 3, got 2)
La portée d’une variable désigne la région du code où cette variable est accessible. En Python, les
portées principales sont :
• Portée locale : Une variable définie à l’intérieur d’une fonction est accessible uniquement
dans cette fonction.
• Portée globale : Une variable définie à l’extérieur de toute fonction est accessible dans tout
le module.
• Portée non locale : Une variable définie dans une fonction englobante (mais pas globale) est
accessible dans une fonction imbriquée.
Dans cet exemple, resultat est une variable locale à la fonction calculer_carre. Elle est créée
lors de l’appel de la fonction et détruite une fois la fonction terminée. Tenter d’accéder à resultat
en dehors de la fonction provoque une NameError, car la variable n’existe pas dans la portée
globale.
Note. Les paramètres d’une fonction, comme nombre dans l’exemple ci-dessus, sont également
considérés comme des variables locales. Ils sont initialisés avec les arguments passés lors de l’appel
et ne sont accessibles qu’à l’intérieur de la fonction.
...
>>> print(calculer_prix_ttc(100))
120.0
Ici, taux_taxe est une variable globale accessible dans la fonction calculer_prix_ttc. La fonc-
tion utilise taux_taxe pour calculer le prix toutes taxes comprises (TTC).
Cependant, si une fonction définit une variable locale avec le même nom qu’une variable globale,
la variable locale masque la variable globale à l’intérieur de la fonction.
>>> message = "Bonjour global" # Variable globale
>>> def afficher_message():
... message = "Bonjour local" # Variable locale
... print(message)
...
>>> afficher_message()
Bonjour local
>>> print(message)
Bonjour global
Dans la fonction afficher_message, la variable message locale prend la précédence sur la variable
message globale. En dehors de la fonction, la variable globale reste inchangée.
Note. Le masquage des variables globales par des variables locales est une source courante
d’erreurs. Évitez d’utiliser le même nom pour des variables locales et globales, sauf si cela est
intentionnel. Préférez des noms descriptifs et distincts pour clarifier l’intention du code.
On remarque que l’assignation compteur = compteur + 1 tente de créer une variable locale
compteur, mais la lecture de compteur avant son assignation provoque une UnboundLocalError.
>>> incrementer()
Compteur : 1
>>> incrementer()
Compteur : 2
>>> print(f"Compteur global : {compteur}")
Compteur global : 2
La déclaration global compteur indique que la fonction doit utiliser la variable globale compteur
plutôt que d’en créer une locale. Chaque appel à incrementer modifie la variable globale.
Note. L’utilisation excessive de variables globales et du mot-clé global peut rendre le code difficile
à comprendre et à maintenir, car les fonctions deviennent dépendantes de l’état global. Préférez
passer les variables comme paramètres et renvoyer les résultats pour des fonctions plus prévisibles.
Dans cet exemple, compteur est défini dans fonction_externe et nonlocal compteur dans
fonction_interne permet de modifier cette variable. Sans nonlocal, une nouvelle variable locale
serait créée dans fonction_interne.
Note. Le mot-clé nonlocal est rarement utilisé dans les programmes simples.
Une fonction récursive est une fonction qui s’appelle elle-même pour résoudre un problème en le
divisant en sous-problèmes plus petits. Toute fonction récursive doit comporter :
• Un cas de base : Une condition qui arrête la récursivité en renvoyant un résultat sans nouvel
appel.
• Un cas récursif : Une étape où la fonction s’appelle avec des arguments modifiés pour
progresser vers le cas de base.
La récursivité repose sur l’idée qu’un problème complexe peut être résolu en le réduisant à des
instances plus simples du même problème, jusqu’à atteindre une solution directe (le cas de base).
Une analogie utile est celle d’une poupée russe : chaque grande poupée contient une version
plus petite d’elle-même, et on continue à ouvrir les poupées jusqu’à atteindre la plus petite qui
ne contient plus rien. Cette dernière représente le cas de base, simple et directement résolu. La
récursivité suit un processus similaire, où chaque appel traite une partie du problème et passe le
reste à un nouvel appel.
Considérons une fonction récursive pour calculer la factorielle d’un nombre n, définie comme
n! = n × (n − 1) × · · · × 1 :
>>> def factorielle(n):
... # Cas de base : 0! = 1
... if n == 0:
... return 1
... # Cas récursif : n! = n * (n−1)!
... return n * factorielle(n − 1)
...
>>> print(factorielle(5))
120
Une fonction lambda peut prendre plusieurs arguments, mais elle ne peut contenir qu’une seule
expression, dont le résultat est implicitement renvoyé. L’évaluation de l’expression constitue donc
la valeur de retour de la fonction.
Les fonctions lambda sont principalement conçues pour être utilisées directement là où elles
sont définies, sans être assignées à une variable. Cela reflète leur objectif : fournir une fonction
temporaire pour un calcul ou une opération immédiate. En enveloppant une fonction lambda dans
des parenthèses et en lui passant immédiatement des arguments, vous pouvez exécuter le calcul en
une seule expression, ce qui est à la fois concis et clair pour des tâches simples.
Voici quelques exemples :
>>> (lambda x: x ** 2)(5)
25
>>> (lambda x: x % 2 == 0)(6)
True
>>> (lambda x, y, z: max(x, y, z))(10, 5, 8)
10
Commentaires
• lambda x: x ** 2 définit une fonction anonyme qui prend un argument x et renvoie son
Il est techniquement possible d’assigner une fonction lambda à une variable, ce qui lui donne un
nom, mais cette pratique est fortement déconseillée par le PEP 8 1 . Lorsqu’une fonction lambda est
assignée à une variable, elle devient similaire à une fonction nommée définie avec def, mais avec
des inconvénients significatifs, notamment des difficultés pour le débogage. Une fonction définie
avec def est alors préférable, car elle offre une meilleure lisibilité et des messages d’erreur plus
explicites.
Illustrons une fonction lambda assignée à une variable (à éviter) :
>>> carre = lambda x: x ** 2
>>> print(carre(5))
25
Cette fonction lambda est assignée à la variable carre, ce qui fonctionne, mais une définition avec
def est recommandée :
La version avec def est plus claire et est conforme aux conventions.
Voici quelques raisons pour éviter d’assigner un nom à une fonction lambda, comme stipulé dans le
PEP 8 :
• Une fonction définie avec def est plus explicite avec un nom descriptif.
• Les fonctions lambda apparaissent comme <lambda> dans les traces d’erreur, ce qui rend
l’identification de l’erreur plus difficile. Une fonction nommée affiche son nom, cela facilite
le diagnostic.
• Assigner un nom à une fonction lambda suggère qu’elle est destinée à un usage répété, ce
qui contredit son rôle de fonction temporaire. Cela peut prêter à confusion pour les autres
programmeurs.
Une trace d’erreur montre les limites des fonctions lambda nommées :
>>> division = lambda x: x / 0
>>> print(division(5))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
1. [Link]
La traceback mentionne <lambda>, ce qui est peu informatif. De plus, l’indication de la ligne
pour l’erreur dans la fonction lambda (line 1) correspond à celle de l’appel et non à celle de la
définition.
Avec une fonction nommée :
>>> def division(x):
... return x / 0
...
>>> print(division(5))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in division
ZeroDivisionError: division by zero
Le nom division aide à repérer l’origine de l’erreur. Et, cette fois-ci, la traceback indique bien la
bonne ligne (line 2) dans la fonction.
Alors, conformément au PEP 8, évitez d’assigner des fonctions lambda à des variables. Si une
fonction doit être réutilisée ou nommée, utilisez def pour définir une fonction nommée, ce qui
améliore la lisibilité, facilite le débogage et respecte les conventions de Python. Les fonctions
lambda sont destinées à des usages temporaires, comme les calculs immédiats illustrés ci-dessous.
La fonction map() prend une fonction et un itérable, applique cette fonction à chaque élément de
l’itérable et produit un itérateur contenant les résultats. Une fonction lambda permet de définir une
transformation simple à appliquer à chaque élément, cela évite la nécessité de créer une fonction
nommée pour une tâche ponctuelle.
Soit cet exemple pour calculer le carré de chaque nombre dans une liste :
>>> nombres = [1, 2, 3, 4]
>>> carres = map(lambda x: x ** 2, nombres)
>>> print(list(carres))
[1, 4, 9, 16]
Dans cet exemple, lambda x: x ** 2 est une fonction anonyme qui prend un argument x et renvoie
son carré. La fonction map() applique cette lambda à chaque élément de nombres et list(carres)
convertit l’itérateur résultant en une liste. Chaque élément de nombres est transformé en son carré :
1 devient 1, 2 devient 4, et ainsi de suite.
Note. La fonction map() renvoie un itérateur, ce qui est efficace pour traiter de grandes collections
sans charger tous les résultats en mémoire immédiatement. Pour voir les résultats, il est nécessaire
2. [Link]
de convertir l’itérateur en une liste avec list(), comme montré dans l’exemple.
La fonction filter() prend une fonction et un itérable et ne conserve que les éléments pour
lesquels la fonction renvoie True. Cela produit un itérateur des éléments sélectionnés. Une fonction
lambda est souvent utilisée pour définir le critère de sélection.
Par exemple, pour sélectionner les nombres pairs dans une liste :
>>> nombres = [1, 2, 3, 4, 5, 6]
>>> pairs = filter(lambda x: x % 2 == 0, nombres)
>>> print(list(pairs))
[2, 4, 6]
Dans cet exemple, lambda x: x % 2 == 0 renvoie True pour les nombres pairs et False sinon.
La fonction filter() conserve uniquement les éléments pour lesquels la lambda renvoie True.
Prenons un autre exemple : sélectionner les chaînes de longueur supérieure à 3 :
>>> mots = ["chat", "chien", "rat", "éléphant"]
>>> longs = filter(lambda x: len(x) > 3, mots)
>>> print(list(longs))
['chat', 'chien', 'éléphant']
La fonction lambda x: len(x) > 3 renvoie True pour les chaînes dont la longueur dépasse 3
caractères et filter() conserve ces éléments.
Note. La fonction passée à filter() doit renvoyer une valeur booléenne (True ou False). Une
fonction lambda qui renvoie une valeur non booléenne peut produire des résultats inattendus, car
Python interprète les valeurs non nulles comme True. Par exemple, lambda x: x conserve tous les
éléments non nuls, ce qui peut ne pas être l’intention.
La fonction sorted() trie les éléments d’un itérable et accepte un paramètre optionnel key qui
spécifie une fonction pour déterminer l’ordre de tri. Une fonction lambda est souvent utilisée
comme argument key pour définir un critère de tri personnalisé. Cela permet de trier selon des
attributs spécifiques des éléments.
Pour trier une liste de chaînes par leur longueur :
>>> fruits = ["pastèque", "banane", "orange", "pomme"]
>>> tries = sorted(fruits, key=lambda x: len(x))
>>> print(tries)
['pomme', 'banane', 'orange', 'pastèque']
Ici, lambda x: len(x) renvoie la longueur de chaque chaîne et sorted() utilise ces longueurs
pour trier la liste en plaçant les chaînes les plus courtes en premier ("pomme" avec 5 lettres, puis
"banane" avec 6 lettres, etc.).
Un autre exemple pour trier une liste de tuples par leur second élément :
>>> paires = [(1, "b"), (3, "a"), (2, "c")]
>>> tries = sorted(paires, key=lambda x: x[1])
>>> print(tries)
[(3, 'a'), (1, 'b'), (2, 'c')]
La fonction lambda x: x[1] extrait le second élément de chaque tuple (les lettres "b", "a", "c")
et sorted() trie les tuples selon ces valeurs en produisant un ordre alphabétique basé sur le second
élément.
Note. La fonction sorted() renvoie une nouvelle liste triée, laissant l’itérable original inchangé.
Cela diffère de la méthode sort() des listes qui modifie la liste en place. Une fonction lambda
utilisée avec key doit renvoyer une valeur comparable, comme un nombre ou une chaîne, pour
garantir un tri cohérent.
En conclusion, l’utilisation des fonctions lambda offre plusieurs avantages significatifs : elles
évitent de définir une fonction nommée pour une tâche simple en rendant le code plus compact ;
elles sont définies exactement là où elles sont utilisées, ce qui peut clarifier l’intention du code pour
des transformations ou critères simples.
Cependant, quelques précautions sont nécessaires. Une fonction lambda complexe (par exemple,
avec des conditions imbriquées comme lambda x: x**2 if x > 0 else −x) peut rendre le code
difficile à lire. Dans ce cas, une fonction nommée avec def est préférable.
>>> nombres = [−2, −1, 0, 1, 2]
>>> transformes = map(lambda x: x**2 + 2*x + 1 if x > 0 else −x**2, nombres)
>>> print(list(transformes))
[−4, −1, 0, 4, 9]
Cette fonction lambda est difficile à comprendre. Une fonction nommée serait plus claire :
>>> def transformation(x):
... if x > 0:
... return x**2 + 2*x + 1
... return −x**2
...
>>> transformes = map(transformation, nombres)
>>> print(list(transformes))
[−4, −1, 0, 4, 9]
Évitez donc d’abuser des fonctions lambda pour des tâches complexes. Si une fonction lambda
dépasse une ligne ou devient difficile à comprendre, convertissez-la en une fonction classique.
Vous avez appris à écrire des programmes Python en utilisant les fonctionnalités de base du langage,
comme les variables, les boucles, les fonctions et les structures de données. Cependant, Python
offre une richesse de fonctionnalités supplémentaires grâce à ses modules qui permettent d’étendre
les capacités du langage en regroupant des fonctions, des classes et des constantes liées à des
tâches spécifiques. Ce chapitre vous introduit à l’utilisation des modules, à leur importation et à
l’exploration de certains modules standards de Python qui sont des outils essentiels pour résoudre
des problèmes variés.
6.1 Modules
Un module est un fichier Python contenant des définitions de fonctions, de classes, de variables
ou d’autres objets, qui peuvent être importés dans un programme pour réutiliser leur contenu. Les
modules permettent d’organiser le code de manière modulaire et de partager des fonctionnalités
entre différents programmes.
Pensez à un module comme à une boîte à outils : chaque module contient un ensemble d’outils
(fonctions, par exemple) adaptés à une tâche particulière, comme générer des nombres aléatoires ou
effectuer des calculs mathématiques. En important un module, vous accédez à ces outils sans avoir
à les recréer.
L’instruction import charge un module dans votre programme et rend ses fonctionnalités dispo-
nibles. La syntaxe de base est :
1 import nom_module
100 Chapitre 6. Modules et fichiers
Pour importer le module math, qui contient des fonctions mathématiques, vous pouvez écrire :
>>> import math
>>> print([Link](16)) # Calcule la racine carrée de 16
4.0
Ici, [Link]() est une fonction du module math. Le point . permet d’accéder aux fonctions ou
variables définies dans le module.
Note. Les modules standards, comme math, font partie de la bibliothèque standard de Python et
sont disponibles dès l’installation de Python. Vous n’avez pas besoin de les installer séparément,
contrairement aux modules externes.
Parfois, vous n’avez besoin que d’une partie spécifique d’un module, comme une fonction ou une
constante particulière. L’instruction from ... import ... permet d’importer uniquement ce dont
vous avez besoin, ce qui rend le code plus lisible et évite de charger l’ensemble du module.
Pour importer uniquement la fonction sqrt du module math :
>>> from math import sqrt
>>> print(sqrt(16)) # Pas besoin d'écrire [Link]
4.0
Vous pouvez importer plusieurs éléments en les séparant par des virgules :
>>> from math import sqrt, pi
>>> print(sqrt(25))
5.0
>>> print(pi)
3.141592653589793
L’instruction from math import * importe toutes les fonctions du module math. On peut alors
utiliser toutes ses fonctions directement.
Note. Évitez d’importer trop d’éléments avec from module import *, car cela peut rendre le
code difficile à lire et provoquer des conflits si plusieurs modules définissent des noms identiques
(par exemple, deux fonctions portant le même nom). Préférez des importations explicites.
L’instruction as permet de donner un alias (un nom alternatif) à un module ou à un élément importé.
Cela est utile pour raccourcir les noms longs ou éviter des conflits.
Pour importer le module math avec l’alias m :
>>> import math as m
>>> print([Link](9))
3.0
Ici, m est un alias pour math, ce qui rend le code plus concis.
Vous pouvez également utiliser as avec from ... import ... :
>>> from math import sqrt as racine
>>> print(racine(16))
4.0
Note. Choisissez des alias courts mais explicites pour maintenir la lisibilité du code. Par exemple,
m est un alias courant pour math, mais r pour sqrt pourrait prêter à confusion.
Le module random fournit des fonctions pour générer des nombres aléatoires, ce qui est utile
dans des applications comme les simulations, les jeux ou les tests de programmes. Il est basé sur
un générateur de nombres pseudo-aléatoires, ce qui signifie que les nombres produits semblent
aléatoires mais sont déterminés par une graine initiale (seed).
Voici quelques fonctions clés du module random :
• random() : Retourne un nombre flottant aléatoire entre 0 (inclus) et 1 (exclus), tiré dans une
distribution uniforme.
• randint(a, b) : Retourne un entier aléatoire entre a et b (inclus), toujours dans une distri-
bution uniforme.
• choice(sequence) : Sélectionne un élément aléatoire dans une séquence (comme une liste
ou un tuple).
Voici un exemple qui illustre l’utilisation de ces fonctions.
>>> import random
>>> print([Link]())
0.24489185380347622
>>> print([Link](1, 6))
2
>>> fruits = ["pomme", "banane", "orange"]
>>> print([Link](fruits))
orange
Note. Les résultats varient à chaque exécution, car les nombres sont générés aléatoirement. Pour
obtenir des résultats reproductibles (par exemple, pour des tests), vous pouvez définir une graine
avec [Link](valeur).
1. [Link]
>>> [Link](42)
>>> [Link](0, 10)
10
>>> [Link](0, 10)
1
>>> [Link](0, 10)
0
Ici, la graine aléatoire est fixée à 42. Si on ne précise pas la graine, par défaut, Python utilise la date,
ou plutôt la timestamp (plus précisément, il s’agit du nombre de secondes écoulées depuis le 1er
janvier 1970). Ainsi, à chaque fois qu’on relance Python, la graine sera différente, car ce nombre
de secondes sera différent.
Si vous exécutez ces mêmes lignes de code (depuis l’instruction [Link](42)), il se peut que
vous ayez des résultats différents selon la version de Python. Néanmoins, vous devriez systémati-
quement obtenir les mêmes résultats si vous relancez plusieurs fois de suite ces instructions sur une
même machine.
Pour explorer d’autres fonctionnalités, comme la génération de nombres selon des distributions
spécifiques (par exemple, gaussienne, exponentielle, binomiale, etc.), consultez la documentation
officielle du module random 2 pour plus de détails.
Le module math fournit des fonctions et des constantes pour effectuer des calculs mathématiques
avancés, comme les opérations trigonométriques, logarithmiques et plein d’autres. Nous avons
donc des constantes comme pi (la constante π), e (la base du logarithme naturel), inf (l’infini),
ainsi que des fonctions comme :
• sqrt(x) : Calcule la racine carrée de x.
• sin(x), cos(x), tan(x) : Fonctions trigonométriques (angles en radians).
• ceil(x), floor(x) : Arrondissent x à l’entier supérieur ou inférieur.
• log(x) : Calcule le logarithme népérien de x.
2. [Link]
Note. Les fonctions trigonométriques du module math attendent des angles en radians, pas en
degrés. Pour convertir des degrés en radians, utilisez [Link](degres). Pour une liste
complète des fonctions du module math, consultez la documentation officielle 3 .
Le module os fournit des fonctions pour interagir avec le système d’exploitation, permettant
d’effectuer des tâches comme la manipulation de fichiers, la navigation dans les répertoires ou
l’exécution de commandes système. Il est utile pour écrire des programmes qui doivent s’adapter à
l’environnement dans lequel ils s’exécutent, comme Windows, Linux ou macOS. Ce module est
un pont entre votre code Python et les fonctionnalités du système d’exploitation. Il contient des
outils pour gérer les fichiers et répertoires, accéder aux variables d’environnement et exécuter des
opérations spécifiques au système d’exploitation. Il permet d’écrire des programmes portables,
c’est-à-dire capables de fonctionner sur différents systèmes avec un minimum d’ajustements.
Voici quelques fonctions principales du module os :
• [Link]() : Retourne le chemin absolu du répertoire de travail courant.
• [Link](path) : Liste les fichiers et répertoires dans le chemin spécifié.
• [Link](path) : Crée un nouveau répertoire au chemin spécifié.
• [Link](*paths) : Combine plusieurs composants de chemin pour former un chemin
valide adapté au système d’exploitation.
Voici un programme qui utilise le module os pour afficher le répertoire de travail courant et lister
son contenu.
>>> import os
>>> print([Link]())
/home/user/projets
>>> print([Link]('.'))
['[Link]', 'data', '[Link]']
Dans cet exemple, [Link]() retourne le chemin absolu du répertoire courant et [Link]
('.') liste les fichiers et dossiers dans ce répertoire. Le point '.' désigne le répertoire courant.
Note. Les chemins de fichiers varient selon les systèmes d’exploitation (par exemple, C:\data sous
Windows, /data sous Linux). Utilisez [Link]() pour construire des chemins portables, car
il adapte automatiquement les séparateurs (\ ou /) au système.
Pour des tâches plus complexes, comme la suppression de répertoires ou la gestion des permis-
sions, consultez la documentation officielle du module os 4 . Le chapitre 8 explorera davantage la
manipulation de fichiers avec os.
Les modules time et datetime permettent de travailler avec le temps et les dates, que ce soit pour
mesurer la durée d’un programme, afficher la date actuelle ou manipuler des intervalles temporels.
Bien que ces modules partagent certaines fonctionnalités, ils ont des objectifs distincts : time est
orienté vers la manipulation de timestamps et la mesure du temps, tandis que datetime est conçu
pour gérer des dates et heures de manière plus simple.
Le module time fournit des fonctions pour accéder au temps système, mesurer des durées et
formater des timestamps. Le module datetime offre des classes pour représenter et manipuler des
3. [Link]
4. [Link]
Le module time est souvent utilisé pour mesurer des durées ou introduire des pauses dans un
programme. Voici quelques fonctions clés :
• [Link]() : Retourne le timestamp actuel (nombre de secondes depuis le 1er janvier 1970,
appelé époque Unix).
• [Link](secondes) : Suspend l’exécution du programme pendant le nombre de se-
condes spécifié.
• [Link]() : Convertit un timestamp en une chaîne de caractères lisible.
Voici un programme qui mesure le temps d’exécution d’une boucle et introduit une pause.
1 import time
2
3 # Mesurer le temps de départ
4 debut = [Link]()
5
6 # Simuler une tâche
7 for _ in range(1000000):
8 pass
9
10 # Mesurer le temps écoulé
11 fin = [Link]()
12 print(f"Temps écoulé : {fin − debut} secondes")
13
14 # Pause de 2 secondes
15 [Link](2)
16 print("Fin de la pause")
Exécution :
Temps écoulé : 0.031142711639404297 secondes
Fin de la pause
Ici, [Link]() est utilisé pour mesurer la durée de la boucle et [Link](2) introduit une
pause de 2 secondes.
Fonctions principales du module datetime
Le module datetime fournit des classes comme datetime, date et timedelta pour manipuler des
dates et heures. Voici quelques fonctionnalités courantes :
• [Link]() : Retourne l’objet datetime représentant la date et l’heure
actuelles.
• [Link]() : Retourne l’objet date de la date actuelle.
• [Link] : Représente une durée (par exemple, 3 jours) pour effectuer des
calculs sur les dates.
Voici un programme qui affiche la date actuelle et calcule une date future.
>>> from datetime import datetime, date, timedelta
>>> print([Link]())
2025−05−05 [Link].384303
>>> print([Link]())
2025−05−05
Dans cet exemple, timedelta(days=7) crée une durée de 7 jours, qui est ajoutée à la date actuelle
pour obtenir une date future.
Note. Les objets datetime et date ne sont pas des chaînes de caractères. Pour les afficher dans un
format spécifique (par exemple, "05/05/2025"), utilisez la méthode strftime(). Par exemple :
>>> print([Link]().strftime("%d/%m/%Y %H:%M"))
05/05/2025 03:03
Pour des manipulations avancées, comme les fuseaux horaires ou les formats de date complexes,
n’hésitez pas à consulter la documentation officielle des modules time 5 et datetime 6 .
Le module copy fournit des outils pour créer des copies d’objets Python, comme les listes, les
dictionnaires ou les objets personnalisés. Comme vous l’avez vu dans la section 4.1.3 sur les listes
imbriquées et la copie, une simple affectation (par exemple, liste2 = liste1) ne crée pas une
nouvelle liste, mais une référence à la même liste. Le module copy permet de résoudre ce problème
en créant des copies indépendantes, soit superficielles, soit profondes.
Les deux fonctions du module copy sont :
• [Link](obj) : Crée une copie superficielle (shallow copy) de l’objet obj.
• [Link](obj) : Crée une copie profonde (deep copy) de l’objet obj, y compris tous
les objets imbriqués.
Considérons une liste imbriquée pour illustrer la différence entre une copie superficielle et une
copie profonde.
1 import copy
2
3 # Liste imbriquée
4 liste_originale = [1, [2, 3], 4]
5
6 # Copie superficielle
7 liste_copie_superficielle = [Link](liste_originale)
8 # Copie profonde
9 liste_copie_profonde = [Link](liste_originale)
10
11 # Modifier la sous−liste dans la liste originale
12 liste_originale[1][0] = 99
13
14 print(liste_originale)
15 print(liste_copie_superficielle)
16 print(liste_copie_profonde)
Exécution :
[1, [99, 3], 4]
[1, [99, 3], 4]
5. [Link]
6. [Link]
La fonction help() est accessible directement dans l’interpréteur Python ou dans un programme.
En passant un module comme argument, elle affiche sa documentation qui inclut souvent une
description générale, une liste des fonctions et des exemples d’utilisation.
Pour obtenir de l’aide sur le module math, par exemple, vous pouvez exécuter la commande suivante
dans l’interpréteur Python :
>>> import math
>>> help(math)
NAME
math
DESCRIPTION
This module provides access to the mathematical functions
defined by the C standard.
FUNCTIONS
acos(x, /)
Return the arc cosine (measured in radians) of x.
acosh(x, /)
asin(x, /)
Return the arc sine (measured in radians) of x.
Cet extrait montre une partie de la documentation du module math qui contient une description et
une liste de fonctions.
Vous pouvez également utiliser help() pour obtenir des informations sur une fonction spécifique
d’un module :
>>> help(math.log10)
Qui renvoie :
Help on built−in function log10 in module math:
log10(x, /)
Return the base 10 logarithm of x.
Note. Dans l’interpréteur Python, help() affiche la documentation de manière interactive, permet-
tant de naviguer avec les touches du clavier.
• Pour vous déplacer dans l’aide, utilisez les flèches du haut et du bas pour le parcourir ligne
par ligne ou les touches Page-up et Page-down pour faire défiler l’aide page par page.
• Pour quitter l’aide, appuyez sur la touche Q.
• Pour chercher du texte, tapez le caractère / puis le texte que vous cherchez, puis la touche
Entrée. Par exemple, pour chercher l’aide sur la fonction factorial(), tapez /factorial
puis Entrée.
La fonction dir() est utile pour explorer rapidement le contenu d’un module sans lire toute sa
documentation. Elle retourne une liste de chaînes représentant les noms des attributs, fonctions et
constantes définis dans le module.
Pour lister les attributs du module random :
>>> import random
>>> print(dir(random))
['BPF', 'LOG4', 'NV_MAGICCONST', 'RECIP_BPF', 'Random', 'SG_MAGICCONST', '
SystemRandom', 'TWOPI', '_ONE', '_Sequence', '__all__', '__builtins__', '
__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__
', '__spec__', '_accumulate', '_acos', '_bisect', '_ceil', '_cos', '_e', '
_exp', '_fabs', '_floor', '_index', '_inst', '_isfinite', '_lgamma', '_log
', '_log2', '_os', '_pi', '_random', '_repeat', '_sha512', '_sin', '_sqrt
', '_test', '_test_generator', '_urandom', '_warn', 'betavariate', '
binomialvariate', 'choice', 'choices', 'expovariate', 'gammavariate', '
gauss', 'getrandbits', 'getstate', 'lognormvariate', 'normalvariate', '
paretovariate', 'randbytes', 'randint', 'random', 'randrange', 'sample', '
seed', 'setstate', 'shuffle', 'triangular', 'uniform', 'vonmisesvariate',
'weibullvariate']
Cette liste affiche des fonctions comme random(), gauss(), choice(), etc., ainsi que des attributs
internes (commençant par _) utilisés par le module.
Un module externe est une bibliothèque Python développée par des tiers et non incluse dans la
bibliothèque standard. Ces modules sont hébergés sur le Python Package Index (PyPI) 7 et peuvent
être installés avec la commande pip.
Pour installer un module externe, vous utilisez pip, un outil en ligne de commande inclus avec
Python. La syntaxe générale pour installer un module est :
$ pip install nom_du_module
Pour installer le module requests qui permet de faire des requêtes HTTP (par exemple, pour récu-
pérer des pages web), exécutez la commande suivante dans votre terminal ou invite de commandes :
$ pip install requests
Une fois installé, vous pouvez importer et utiliser le module dans votre programme :
>>> import requests
>>> reponse = [Link]('[Link]
>>> print(reponse.status_code)
200
Ici, [Link]() envoie une requête à l’API de GitHub et status_code indique si la requête a
réussi (200 signifie succès).
Note. Assurez-vous que pip correspond à la version de Python que vous utilisez. Par exemple,
si vous utilisez Python 3 sur Linux ou macOS, exécutez pip3 install nom_du_module. Vous
pouvez vérifier la version avec pip −−version. Généralement, c’est pip qui est utilisé.
7. [Link]
$ pip3 list
Package Version
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− −−−−−−−−−−−−
anonip 1.1.0
base58 1.0.3
cryptography 43.0.0
[...]
Voici quelques modules externes couramment utilisés dont certains seront davantage explorés dans
les chapitres suivants :
• numpy : Pour les calculs numériques et la manipulation de tableaux.
• matplotlib : Pour créer des graphiques et des visualisations.
• pandas : Pour l’analyse et la manipulation de données tabulaires.
• requests : Pour interagir avec des services web via des requêtes HTTP.
• scikit−learn : Pour l’apprentissage automatique (machine learning).
• tensorflow : Pour construire et entraîner des modèles de deep learning à grande échelle.
• torch : Pour le développement flexible et rapide de modèles de deep learning.
• seaborn : Pour créer des visualisations statistiques élégantes (basé sur matplotlib).
• sympy : Pour effectuer du calcul symbolique (mathématiques formelles).
• opencv−python : Pour le traitement d’images et la vision par ordinateur.
Note. Les modules externes peuvent avoir des dépendances (autres modules nécessaires à leur fonc-
tionnement). pip les installe automatiquement, mais vérifiez les messages d’erreur si l’installation
échoue.
4
5 # Fonctions
6 def carre(nombre):
7 """Retourne le carré d'un nombre."""
8 return nombre ** 2
9
10 def aire_cercle(rayon):
11 """Calcule l'aire d'un cercle à partir de son rayon."""
12 return PI * rayon ** 2
13
14 def energie_potentielle(masse, hauteur):
15 """Calcule l'énergie potentielle (E = mgh)."""
16 return masse * GRAVITE * hauteur
Vous pouvez ensuite utiliser ce module dans un autre programme, par exemple, [Link] :
1 import calculs
2
3 print(f"Carré de 5 : {[Link](5)}")
4 print(f"Aire d'un cercle de rayon 3 : {calculs.aire_cercle(3):.4f}")
5 print(f"Énergie potentielle (m=2kg, h=10m) : {calculs.energie_potentielle(2,
10):.4f}")
6 print(f"Constante de gravité : {[Link]}")
Dans cet exemple, le module calculs définit deux constantes PI et GRAVITE, ainsi que trois
fonctions carre(), aire_cercle() et energie_potentielle(), qui sont accessibles via calculs
.nom après importation.
Notes.
1. Les constantes, bien que Python ne les rende pas réellement immuables, sont des variables
dont la valeur ne devrait pas changer. Par convention, elles sont nommées en majuscules (par
exemple, PI) et utilisées pour stocker des valeurs fixes. Il faut noter que les constantes en Py-
thon peuvent être modifiées, car il n’existe pas de mécanisme natif pour les rendre immuables.
Par convention, respectez leur usage en ne les modifiant pas dans vos programmes.
2. Les modules doivent être dans le même répertoire que le programme qui les importe ou dans
un chemin accessible par Python. Vous pouvez également utiliser from calculs import
carre pour importer uniquement une fonction spécifique.
3. La première fois qu’un module est importé, Python crée un répertoire nommé __pycache__
contenant un fichier avec une extension .pyc qui contient le bytecode 8 , c’est-à-dire le code
pré-compilé du module.
Un module Python, comme vu dans les paragraphes précédents, est généralement constitué de
définitions telles que des fonctions ou des constantes. Lorsqu’un tel module est importé dans
8. [Link]
un autre programme, ces définitions sont chargées en mémoire, mais aucun code n’est exécuté
automatiquement, ce qui garantit que le module agit comme une bibliothèque d’outils prêts à
l’emploi. Cependant, si vous incluez du code exécutable, comme des appels à print() ou des
calculs, directement dans le module, ce code s’exécutera dès que le module est importé, ce qui peut
entraîner des comportements inattendus comme des affichages indésirables ou une consommation
inutile de mémoire
Lorsqu’un module ne contient que des définitions, son importation charge ces définitions en
mémoire sans provoquer d’effet immédiat. Cela garantit que le module peut être utilisé comme
une bibliothèque, où les fonctions ou constantes sont disponibles mais n’agissent que lorsqu’elles
sont explicitement appelées. Si on l’exécutait comme un script classique, cela n’afficherait rien, par
exemple :
$ python3 [Link]
$
Mais si vous ajoutez du code exécutable directement dans un module, ce code s’exécute automati-
quement chaque fois que le module est importé, ce qui peut produire des effets indésirables, comme
des affichages non souhaités, des calculs inutiles ou des modifications de données.
Modifions [Link] pour inclure du code exécutable :
1 PI = 3.14159
2
3 def aire_cercle(rayon):
4 """Calcule l'aire d'un cercle à partir de son rayon."""
5 return PI * rayon ** 2
6
7 # Code exécutable
8 print("Module calculs chargé.")
9 resultat = aire_cercle(5)
10 print(f"Aire d'un cercle de rayon 5 : {resultat:.4f}")
Puis exécutez-le :
$ python3 [Link]
Module calculs chargé.
Aire d'un cercle de rayon 5 : 78.5397
Programme principal : Aire pour rayon 2 : 12.5664
l’exécution du code aux cas où le module est exécuté directement, souvent pour des tests ou des
démonstrations.
Modifions [Link] pour utiliser if __name__ == "__main__": :
1 PI = 3.14159
2
3 def aire_cercle(rayon):
4 """Calcule l'aire d'un cercle à partir de son rayon."""
5 return PI * rayon ** 2
6
7 if __name__ == "__main__":
8 print("Module calculs exécuté directement.")
9 resultat = aire_cercle(5)
10 print("Aire d'un cercle de rayon 5 :", resultat)
Puis exécutez-le :
$ python3 [Link]
Programme principal : Aire pour rayon 2 : 12.5663
Dans ce cas, le code dans if __name__ == "__main__": ne s’exécute pas lors de l’importation,
car __name__ vaut "calculs". Cela permet d’inclure des tests ou des exemples dans le module
sans affecter les programmes qui l’importent. On peut vérifier le comportement des fonctions du
module sans écrire un programme séparé.
Une docstring est une chaîne de caractères, délimitée par des triples guillemets (""" ou '''),
placée immédiatement après la définition d’un module, d’une fonction ou d’une classe, pour
décrire son objectif, ses paramètres et son comportement. La documentation contient également
des commentaires et des guides externes pour expliquer le code.
Une docstring doit être claire, concise et suivre les conventions de Python, notamment la norme
Vous pouvez accéder aux docstrings avec la fonction help() ou l’attribut __doc__ :
>>> import traitement_texte
>>> help(traitement_texte)
NAME
traitement_texte − Module pour le traitement avancé des chaînes de caractè
res.
DESCRIPTION
Ce module fournit des fonctions pour nettoyer et analyser du texte, utiles
9. [Link]
pour
le prétraitement de données textuelles ou la validation d'entrées
utilisateur.
FUNCTIONS
compter_mots(texte)
Compte le nombre de mots dans une chaîne.
Un mot est défini comme une séquence de caractères séparée par des
espaces.
Args:
texte (str): La chaîne à analyser.
Returns:
int: Le nombre de mots dans la chaîne.
nettoyer_texte(texte)
Convertit une chaîne en minuscules et supprime les espaces inutiles.
Args:
texte (str): La chaîne à nettoyer.
Returns:
str: La chaîne nettoyée, en minuscules et sans espaces au début ou
à la fin.
Example:
>>> nettoyer_texte(" Bonjour ! ")
'bonjour !'
FILE
/home/user/projets/traitement_texte.py
Vous remarquez que Python a généré automatiquement cette page d’aide, tout comme il est capable
de le faire pour les modules internes à Python (random, math, etc.) et ce, grâce aux docstrings.
Note. Les docstrings sont très utiles dans les environnements de développement comme VSCode, où
elles apparaissent sous forme d’infobulles lorsque vous survolez une fonction. Une documentation
absente ou obsolète peut rendre un module inutilisable, surtout dans un contexte collaboratif.
Prenez le temps de documenter votre code dès sa création, car il est plus difficile d’ajouter une
documentation complète après coup.
Voici quelques recommandations pour une documentation efficace :
• Écrivez des docstrings pour chaque module, fonction et classe, même si leur rôle semble
évident.
• Utilisez un langage clair et évitez le jargon technique inutile.
• Incluez des exemples dans les docstrings pour illustrer l’utilisation des fonctions.
• Mettez à jour la documentation chaque fois que vous modifiez le code pour éviter les
incohérences.
6.3 Fichiers
Les programmes que vous avez écrits jusqu’à présent manipulaient des données temporaires,
stockées en mémoire dans des variables, des listes ou des dictionnaires. Cependant, dans de
nombreuses applications, il est nécessaire de sauvegarder des données de manière permanente ou
de lire des informations stockées sur le disque, par exemple dans des fichiers texte. La manipulation
de fichiers est ainsi une tâche courante en programmation, que ce soit pour enregistrer des résultats,
lire des données expérimentales ou configurer une application. Python facilite cette tâche grâce à la
fonction open() qui permet d’accéder à un fichier pour le lire, l’écrire ou les deux.
• path : Le chemin vers le fichier qui peut être relatif (par exemple, [Link]) ou absolu
(par exemple, /home/user/[Link]). Utilisez [Link]() pour construire des
chemins portables.
• mode : Une chaîne spécifiant le mode d’ouverture, comme 'r' pour la lecture ou 'w' pour
l’écriture.
Les méthodes principales d’un objet fichier sont :
• read() : Lit tout le contenu du fichier sous forme de chaîne (ou de bytes en mode binaire).
• readline() : Lit une ligne du fichier à la fois.
• readlines() : Lit toutes les lignes du fichier et les retourne sous forme de liste de chaînes.
• write(text) : Écrit du texte (ou des bytes) dans le fichier.
• close() : Ferme le fichier, libérant les ressources.
Supposons que vous ayez un fichier texte nommé [Link] avec le contenu suivant :
pomme
banane
orange
ananas
mangue
Voici un programme qui lit et affiche tout le contenu de ce fichier à l’aide de read() :
>>> fichier = open('[Link]', 'r')
>>> contenu = [Link]()
>>> print(contenu)
pomme
banane
orange
ananas
mangue
>>> [Link]()
Dans cet exemple, read() récupère tout le contenu du fichier comme une seule chaîne avec les
sauts de ligne (\n). La méthode close() est appelée manuellement pour fermer le fichier.
Note. Oublier d’appeler close() peut entraîner des problèmes, comme des données non enregis-
trées ou des ressources système bloquées. Le gestionnaire de contexte with est recommandé pour
éviter ces erreurs.
Le gestionnaire de contexte with garantit que le fichier est fermé automatiquement à la fin du bloc,
même si une erreur survient. Sa syntaxe est :
1 with open(path, mode) as variable:
2 # Instructions
Une fois sorti du bloc d’instructions, Python fermera automatiquement le fichier. Vous n’avez donc
plus besoin d’utiliser la méthode .close().
La méthode strip() supprime les sauts de ligne pour un affichage plus propre. Si vous appelez
readline() après la dernière ligne, elle retourne une chaîne vide ('').
readlines() La méthode readlines() lit toutes les lignes du fichier et les retourne sous forme
de liste, chaque élément étant une chaîne représentant une ligne (avec \n). Elle est pratique lorsque
vous souhaitez stocker toutes les lignes pour un traitement ultérieur.
>>> with open('[Link]', 'r') as fichier:
... lignes = [Link]()
... print(lignes)
...
['pomme\n', 'banane\n', 'orange\n', 'ananas\n', 'mangue\n']
Pour supprimer les sauts de ligne, vous pouvez utiliser une compréhension de liste :
>>> with open('[Link]', 'r') as fichier:
... lignes = [[Link]() for ligne in [Link]()]
... print(lignes)
...
['pomme', 'banane', 'orange', 'ananas', 'mangue']
Note. La méthode readlines() charge toutes les lignes en mémoire, ce qui peut être problématique
pour les fichiers très volumineux. Une boucle for sur l’objet fichier est souvent plus efficace, comme
expliqué ci-dessous.
Une méthode efficace pour lire un fichier volumineux est d’itérer directement sur l’objet fichier
avec une boucle for. Cela lit une ligne à la fois et réduit la consommation de mémoire.
>>> with open('[Link]', 'r') as fichier:
... for ligne in fichier:
... print([Link]())
...
pomme
banane
orange
ananas
mangue
Chaque itération de la boucle récupère une ligne, incluant le saut de ligne, que strip() supprime
pour l’affichage.
Note. Les lignes lues via readline(), readlines() ou une boucle for incluent le caractère de
saut de ligne (\n), sauf pour la dernière ligne si elle ne se termine pas par \n. Utilisez strip() ou
rstrip() pour les supprimer si nécessaire.
• 'r' : Mode lecture (par défaut). Ouvre le fichier pour la lecture uniquement. Si le fichier
n’existe pas, une erreur FileNotFoundError est levée.
• 'w' : Mode écriture. Ouvre le fichier pour l’écriture, créant un nouveau fichier ou remplaçant
un fichier existant.
• 'a' : Mode ajout. Ouvre le fichier pour ajouter du contenu à la fin, créant un nouveau fichier
si nécessaire.
Voici un programme qui illustre les modes w et a :
1 # Écriture : remplace ou crée le fichier
2 with open('[Link]', 'w') as fichier:
3 [Link]("Entrée 1\n")
4
5 # Ajout : ajoute à la fin du fichier
6 with open('[Link]', 'a') as fichier:
7 [Link]("Entrée 2\n")
Si vous exécutez à nouveau le mode w, le fichier est remplacé, tandis que le mode a ajoute à la fin
sans affecter le contenu existant.
Notes.
1. Le mode w écrase tout contenu existant sans avertissement. Utilisez a pour préserver le
contenu et ajouter de nouvelles données.
2. Vous pouvez combiner les modes pour des besoins spécifiques, comme 'r+' (lecture et
écriture) ou 'x' pour la création exclusive. Cependant, ces modes sont moins courants
pour les débutants. Mais si vous voulez approfondir votre compréhension des modes et des
opérations sur les fichiers, consultez la documentation officielle de Python 10 .
10. [Link]
Chacune de ces bibliothèques a été conçue pour interagir harmonieusement avec les autres, vous
permettant de construire des projets scientifiques complets, de la manipulation des données à leur
visualisation. Dans les sections suivantes, vous commencerez par explorer NumPy qui constitue la
fondation de ces outils.
Cette commande télécharge et installe les versions les plus récentes de ces bibliothèques, compa-
tibles avec Python 3.10 ou supérieur 1 . Si vous utilisez conda, la commande équivalente est :
1 conda install numpy matplotlib pandas
Une fois l’installation terminée, vous devez vérifier que les bibliothèques sont correctement instal-
lées. Pour cela, ouvrez un interpréteur Python (par exemple, en tapant python dans le terminal) et
essayez d’importer chaque bibliothèque :
>>> import numpy
>>> import matplotlib
>>> import pandas
Si aucune erreur n’apparaît, les bibliothèques sont prêtes à l’emploi. En pratique, vous utiliserez
souvent des alias pour simplifier vos scripts, comme np pour NumPy. Par exemple :
>>> import numpy as np
>>> print(np.__version__)
2.2.4
Cette commande affiche la version de NumPy installée, ce qui est utile pour vérifier la compatibilité
avec vos scripts. Si une erreur survient lors de l’importation (par exemple, ModuleNotFoundError),
assurez-vous que l’installation a réussi et que vous utilisez le bon environnement Python (certains
systèmes peuvent avoir plusieurs versions de Python installées).
Note. Il est important d’utiliser une version récente de Python (3.10 ou supérieure) pour garantir
la compatibilité avec les dernières versions des bibliothèques. Si vous rencontrez des problèmes
d’installation, vérifiez que pip ou conda est associé à la bonne version de Python en exécutant
pip −−version ou conda −−version dans le terminal.
Vous êtes maintenant prêts à explorer les fonctionnalités de ces bibliothèques, en commençant par
NumPy dans la section suivante. Les outils installés vous permettront de manipuler des données, de
réaliser des calculs scientifiques et de visualiser vos résultats avec aisance.
[5, 7, 9]
[5 7 9]
Dans l’exemple avec NumPy, l’opération + est appliquée simultanément à tous les éléments, sans
boucle explicite, ce qui est non seulement plus concis, mais aussi beaucoup plus rapide pour de
2. [Link]
grands ensembles de données. Cette capacité à effectuer des opérations vectorisées fait de NumPy
un outil indispensable pour le calcul scientifique.
[Link] Création de tableaux et matrices : array, zeros, ones, arange, linspace, eye, diag,
full, tile
La création de tableaux est la première étape pour exploiter la puissance de NumPy. La bibliothèque
propose plusieurs fonctions pour générer des ndarray avec des structures et des contenus variés,
adaptées à différentes applications scientifiques. Nous commencerons par la fonction array qui
convertit une liste Python (ou une liste imbriquée) en un ndarray.
Pour créer un tableau à une dimension, représentant par exemple une série de mesures, vous pouvez
utiliser :
>>> import numpy as np
>>> valeurs = [1.5, 2.7, 3.2]
>>> tableau = [Link](valeurs)
>>> print(tableau)
[1.5 2.7 3.2]
Pour une matrice (tableau à deux dimensions), utilisez une liste imbriquée. Par exemple, pour
représenter une matrice 2x3 :
>>> matrice = [Link]([[1, 2, 3], [4, 5, 6]])
>>> print(matrice)
[[1 2 3]
[4 5 6]]
Notes.
• Lors de la création d’un tableau avec array, assurez-vous que les listes imbriquées ont des
longueurs cohérentes. Par exemple, [Link]([[1, 2], [3]]) générera une erreur ou un
tableau irrégulier, car les sous-listes n’ont pas la même taille.
• Les tableaux NumPy sont homogènes, c’est-à-dire que tous leurs éléments doivent être du
même type. Si vous créez un tableau à partir d’une liste contenant des entiers et des flottants,
NumPy convertit automatiquement tous les éléments en flottants pour préserver la précision.
Par exemple :
>>> mixte = [Link]([1, 2, 3.5])
>>> print(mixte)
[1. 2. 3.5]
Si des chaînes de caractères sont incluses, tous les éléments sont convertis en chaînes :
>>> mixte_texte = [Link]([1, 2, "tigre"])
>>> print(mixte_texte)
['1' '2' 'tigre']
Pour initialiser des tableaux avec des valeurs prédéfinies, NumPy propose zeros et ones. La fonction
zeros crée un tableau rempli de zéros, utile pour initialiser des matrices avant de les remplir :
>>> [Link]((2))
array([0., 0.])
>>> [Link]((2, 3))
La fonction ones crée un tableau rempli de uns, souvent utilisé pour des calculs normalisés :
>>> [Link]((3))
array([1., 1., 1.])
>>> [Link]((3, 2))
array([[1., 1.],
[1., 1.],
[1., 1.]])
La fonction full remplit un tableau avec une valeur spécifique, par exemple pour initialiser une
matrice avec une constante :
>>> [Link]((4), 5)
array([5, 5, 5, 5])
>>> [Link]((2, 2), 5)
array([[5, 5],
[5, 5]])
Pour générer des séquences numériques, arange et linspace sont particulièrement utiles. La
fonction arange crée un tableau à une dimension avec des valeurs espacées régulièrement, en
spécifiant un début, une fin (exclue) et un pas, similaire à range. Par exemple, pour créer une
séquence de 0 à 9 avec un pas de 2 :
>>> [Link](0, 10, 2)
array([0, 2, 4, 6, 8])
La fonction linspace génère un tableau avec un nombre donné de points équidistants entre deux
bornes (incluses). Elle est idéale pour créer des axes pour des graphiques. Par exemple, pour générer
5 points entre 0 et 1 :
>>> [Link](0, 1, 5)
array([0. , 0.25, 0.5 , 0.75, 1. ])
Pour des matrices spécifiques en algèbre linéaire, eye et diag sont essentielles. La fonction eye
crée une matrice identité, avec des 1 sur la diagonale principale et des 0 ailleurs :
>>> [Link](3)
array([[1., 0., 0.],
[0., 1., 0.],
[0., 0., 1.]])
La fonction diag crée une matrice diagonale à partir d’une liste de valeurs, ou extrait la diagonale
d’une matrice existante. Par exemple :
>>> [Link]([1, 2, 3])
array([[1, 0, 0],
[0, 2, 0],
[0, 0, 3]])
>>> [Link]([Link]([1, 2, 3]))
array([1, 2, 3])
La fonction tile répète un tableau ou une séquence selon un motif spécifié, utile pour créer des
structures répétitives. Par exemple, pour répéter le vecteur [1, 2] trois fois :
>>> [Link]([1, 2], 3)
array([1, 2, 1, 2, 1, 2])
Ces fonctions vous permettent de créer des tableaux adaptés à une grande variété de besoins, qu’il
s’agisse de modéliser des données expérimentales, de préparer des calculs matriciels ou de générer
des séquences pour des visualisations. Dans la sous-sous-section suivante, vous explorerez les
propriétés de ces tableaux, comme leur forme et leur type de données, pour mieux comprendre et
manipuler leur structure.
Une fois un tableau ndarray créé, il est essentiel de comprendre ses caractéristiques pour pouvoir
le manipuler efficacement. NumPy fournit plusieurs attributs permettant d’explorer la structure et le
contenu d’un tableau : shape, ndim, size et dtype.
L’attribut shape retourne un tuple indiquant le nombre d’éléments dans chaque dimension du
tableau. Par exemple, pour un tableau à une dimension, shape donne la longueur du tableau. Pour
une matrice, il indique le nombre de lignes et de colonnes. Considérons l’exemple suivant :
>>> tableau_1d = [Link]([1, 2, 3, 4])
>>> tableau_1d.shape
(4,)
>>> [Link]
(2, 3)
Le résultat (4,) signifie que le tableau a une dimension avec 4 éléments. (2, 3) indique 2 lignes
et 3 colonnes.
L’attribut ndim donne le nombre de dimensions du tableau, c’est-à-dire le nombre d’axes ou de
niveaux d’organisation. Il correspond à la longueur du tuple retourné par shape. Par exemple :
>>> tableau_1d.ndim
1
>>> [Link]
2
Pour un tableau à trois dimensions, comme un cube de données, ndim serait 3. Cet attribut est utile
pour vérifier si un tableau a la structure attendue avant d’effectuer des opérations complexes.
L’attribut size retourne le nombre total d’éléments dans le tableau, quelle que soit sa forme. Il
s’agit du produit des valeurs dans shape. Par exemple :
>>> tableau_1d.size
4
>>> [Link]
6
Cet attribut est pratique pour évaluer la taille globale d’un tableau, par exemple pour vérifier la
cohérence des données.
L’attribut dtype indique le type de données des éléments du tableau, comme les entiers (int64),
les nombres à virgule flottante (float64) ou d’autres types spécifiques. Le type est déterminé
automatiquement lors de la création du tableau, en fonction des valeurs fournies, mais peut être
spécifié explicitement pour des besoins particuliers. Par exemple :
1 tableau_entiers = [Link]([1, 2, 3])
2 tableau_flottants = [Link]([1.5, 2.7, 3.2])
3 print(tableau_entiers.dtype)
4 print(tableau_flottants.dtype)
Vous pouvez forcer un type spécifique avec l’argument dtype lors de la création du tableau. Par
exemple, pour créer un tableau d’entiers 32 bits :
>>> tableau_int32 = [Link]([1, 9, −8], dtype=np.int32)
>>> tableau_int32.dtype
dtype('int32')
Le choix du dtype est important dans les calculs scientifiques, car il affecte la précision et la
mémoire utilisée. Par exemple, float32 consomme moins de mémoire que float64, mais offre
une précision moindre, ce qui peut être important pour des simulations numériques 3 .
Ces informations vous permettent de comprendre pleinement la structure du tableau et de vous
assurer qu’il est adapté à vos besoins, que ce soit pour des calculs mathématiques ou des analyses
de données.
Les opérations arithmétiques dans NumPy, telles que l’addition, la soustraction, la multiplication, la
division et l’exponentiation, sont appliquées élément par élément, c’est-à-dire que chaque élément
d’un tableau est traité individuellement avec l’élément correspondant d’un autre tableau ou avec
une constante. Cette approche, appelée vectorisation, élimine le besoin de boucles explicites et rend
le code à la fois plus concis et beaucoup plus rapide qu’avec des listes Python.
Considérons deux tableaux de même forme, représentant par exemple des mesures de température
à deux moments différents. Pour calculer la différence entre ces mesures, vous pouvez utiliser
l’opérateur − :
>>> temp_matin = [Link]([20.5, 21.0, 19.8])
>>> temp_soir = [Link]([22.5, 23.0, 21.5])
>>> temp_soir − temp_matin
array([2. , 2. , 1.7])
Dans cet exemple, chaque élément de temp_soir est soustrait de l’élément correspondant de
temp_matin. Cette opération élément par élément s’applique à tous les opérateurs arithmétiques
standards :
• Addition (+) : a + b additionne les éléments correspondants.
• Soustraction (−) : a − b soustrait les éléments correspondants.
• Multiplication (*) : a * b multiplie les éléments correspondants.
• Division (/) : a / b divise les éléments correspondants.
• Division entière (//) : a // b effectue la division entière des éléments correspondants.
• Exponentiation (**) : a ** b élève chaque élément à la puissance correspondante.
Par exemple, pour multiplier deux matrices élément par élément :
>>> matrice1 = [Link]([[1, 2], [3, 4]])
>>> matrice2 = [Link]([[5, 6], [7, 8]])
>>> matrice1 * matrice2
array([[ 5, 12],
[21, 32]])
Ici, chaque élément est multiplié individuellement. Notez que cette multiplication élément par
élément diffère du produit matriciel classique qui sera abordé dans la sous-section sur l’algèbre
linéaire.
Note. Les tableaux doivent avoir la même forme (shape) pour les opérations élément par élément.
Si les formes diffèrent, NumPy générera une erreur, sauf si le broadcasting s’applique, comme
expliqué ci-dessous. Vérifiez toujours la propriété shape avant d’effectuer des calculs entre plusieurs
tableaux.
Les opérations élément par élément peuvent également impliquer une constante, appelée scalaire.
Dans ce cas, l’opération est appliquée à chaque élément du tableau. Par exemple, pour augmenter
toutes les températures de 2 degrés :
>>> temp_matin = [Link]([20.5, 21.0, 19.8])
>>> temp_matin + 2
array([22.5, 23. , 21.8])
Cette opération est rendue possible par le mécanisme de broadcasting qui permet à NumPy d’adapter
automatiquement un scalaire ou un tableau de forme différente pour qu’il soit compatible avec un
autre tableau. Le broadcasting est une fonctionnalité puissante, mais parfois complexe, qui mérite
une explication détaillée.
Le broadcasting intervient lorsque deux tableaux de formes différentes sont utilisés dans une
opération arithmétique. NumPy tente d’aligner leurs dimensions en « étendant » le tableau de plus
petite dimension, sans dupliquer physiquement les données en mémoire. Les règles du broadcasting
sont les suivantes :
1. Si les tableaux ont un nombre différent de dimensions, le tableau avec moins de dimensions
est complété par des dimensions de taille 1 à gauche.
2. Les dimensions des deux tableaux sont comparées : elles sont compatibles si elles sont égales
Ici, le vecteur de forme (3,) est broadcasté pour correspondre à la forme de la matrice (2, 3).
NumPy interprète le vecteur comme une matrice (1, 3) puis répète implicitement cette ligne pour
obtenir une matrice (2, 3), permettant la multiplication élément par élément. Le calcul peut être
visualisé ainsi :
• Pour la première ligne : [1, 2, 3] * [10, 20, 30] = [10, 40, 90].
• Pour la deuxième ligne : [4, 5, 6] * [10, 20, 30] = [40, 100, 180].
Un autre exemple courant est l’addition d’un scalaire à une matrice, où le scalaire est broadcasté à
toutes les positions :
>>> matrice = [Link]([[1, 2], [3, 4]])
>>> matrice + 10
array([[11, 12],
[13, 14]])
Le scalaire 10 est étendu à une matrice (2, 2) contenant des 10, permettant l’addition élément par
élément. Il en est de même pour les autres opérations (*, /, //, **).
Note. Le broadcasting peut produire des erreurs si les formes ne sont pas compatibles. Par exemple,
multiplier une matrice (2, 3) par un vecteur (2,) générera une erreur, car les dimensions ne
s’alignent pas.
Le tableau initial de forme (6,) est redimensionné en une matrice de forme (2, 3), car 2 * 3 =
[Link] éléments sont disposés ligne par ligne dans la nouvelle structure. Vous pouvez également
redimensionner dans l’autre sens, par exemple pour aplatir une matrice en un vecteur :
>>> matrice = [Link]([[1, 2, 3], [4, 5, 6]])
Si vous ne connaissez pas la taille exacte d’une dimension, vous pouvez utiliser −1 pour lais-
ser NumPy calculer automatiquement la valeur appropriée, tant que les autres dimensions sont
compatibles. Par exemple :
>>> matrice = [Link]([[1, 2, 3], [4, 5, 6]])
>>> tableau = [Link]((3, −1))
>>> print(tableau)
[[1 2]
[3 4]
[5 6]]
Ici, −1 indique que la deuxième dimension doit être calculée pour préserver les 6 éléments, donnant
une forme (3, 2), car 3 * 2 = 6.
Pour aplatir complètement un tableau multidimensionnel en un vecteur à une dimension, NumPy
propose ravel et flatten. La fonction ravel retourne une vue du tableau aplati, tandis que
flatten crée une copie indépendante. Par exemple :
La différence entre ravel et flatten réside dans la gestion de la mémoire : modifier aplati_ravel
affecte la matrice originale, car il s’agit d’une vue (i.e. une copie par référence), tandis que
aplati_flatten est une copie indépendante.
Note. Lors du redimensionnement, assurez-vous que la nouvelle forme est compatible avec le
nombre total d’éléments (size). Par exemple, redimensionner un tableau de 6 éléments en une
matrice (2, 4) générera une erreur, car 2 * 4 = 8 \neq 6.
Concaténation des tableaux La concaténation permet de combiner plusieurs tableaux pour
former un tableau unique, ce qui est utile pour regrouper des données provenant de différentes
sources, comme des mesures expérimentales effectuées à des moments distincts. NumPy propose
plusieurs fonctions pour cela, notamment concatenate, hstack et vstack, chacune adaptée à des
cas spécifiques.
La fonction concatenate ou concatcombine des tableaux le long d’un axe existant, spécifié par le
paramètre axis. Considérons deux matrices 2x2 que nous souhaitons concaténer horizontalement
(le long de l’axe des colonnes, axis=1) :
>>> matrice1 = [Link]([[1, 2], [3, 4]])
>>> matrice2 = [Link]([[5, 6], [7, 8]])
>>> concat_horizontal = [Link]((matrice1, matrice2), axis=1)
>>> print(concat_horizontal)
[[1 2 5 6]
[3 4 7 8]]
Pour une concaténation verticale (le long de l’axe des lignes, axis=0) :
Les fonctions hstack (concaténation horizontale) et vstack (concaténation verticale) sont des rac-
courcis pour concatenate avec axis=1 et axis=0, respectivement, mais elles s’adaptent automati-
quement aux dimensions des tableaux. Par exemple, pour concaténer deux vecteurs horizontalement
ou verticalement :
>>> vecteur1 = [Link]([1, 2])
>>> vecteur2 = [Link]([3, 4])
>>> hstack_result = [Link]((vecteur1, vecteur2))
>>> print(hstack_result)
[1 2 3 4]
>>> vstack_result = [Link]((vecteur1, vecteur2))
>>> print(vstack_result)
[[1 2]
[3 4]]
Note. Pour la concaténation, les tableaux doivent avoir des dimensions compatibles le long des
axes non concernés. Pour une concaténation horizontale, le nombre de lignes doit être identique ; et
pour une concaténation verticale, le nombre de colonnes doit être identique.
Ici, temperatures[1] retourne le deuxième élément, 21.0. Les indices négatifs permettent d’accé-
der aux éléments en partant de la fin : temperatures[−1] retourne 22.3, le dernier élément.
Pour une matrice (tableau à deux dimensions), l’indexation utilise deux indices séparés par une
virgule : le premier pour la ligne, le second pour la colonne. Par exemple, pour une matrice 2x3 :
>>> matrice = [Link]([[1, 2, 3], [4, 5, 6]])
>>> print(matrice[1, 2])
6
(indice 2). Vous pouvez également utiliser des indices négatifs, comme matrice[−1, −1] pour
obtenir le même élément (6). La syntaxe a[i, j] renvoie donc l’élément à la ligne d’indice i et à
la colonne d’indice j.
Indexation avancée L’indexation avancée, également appelée indexation par tableaux ou indexa-
tion sophistiquée, permet d’accéder à plusieurs éléments simultanément en utilisant des listes ou
des tableaux d’indices. Cette technique est puissante pour extraire des sous-ensembles spécifiques.
Par exemple, pour extraire les première et troisième températures :
>>> temperatures = [Link]([20.5, 21.0, 19.8, 22.3])
>>> indices = [0, 2]
>>> selection = temperatures[indices]
>>> print(selection)
[20.5 19.8]
Pour une matrice, vous pouvez spécifier des listes d’indices pour les lignes et les colonnes. Par
exemple, pour extraire les éléments aux positions (0,1) et (-1,2) :
>>> matrice = [Link]([[1, 2, 3], [4, 5, 6]])
>>> elements = matrice[[0, −1], [1, 2]]
>>> print(elements)
[2 6]
Ici, matrice[[0, 1], [−1, 2]] sélectionne les éléments matrice[0, 1] et matrice[−1, 2].
Cette forme d’indexation est utile pour extraire des données non contiguës, comme des points
spécifiques dans un ensemble de mesures.
Notes.
• Lors de l’indexation avancée, assurez-vous que les listes d’indices ont la même longueur
pour les dimensions correspondantes. Par exemple, matrice[[0, 1], [0]] générera une
erreur, car les listes [0, 1] et [0] n’ont pas la même taille.
• Avec deux tableaux A et B, matrice[A, B] retourne un tableau avec les éléments aux posi-
tions matrice[A[0], B[0]], matrice[A[1], B[1]], etc.
Le slicing (ou découpage) permet d’extraire des sous-tableaux en spécifiant des plages d’indices,
de manière similaire aux listes Python, mais avec une syntaxe plus puissante pour les tableaux
multidimensionnels. La syntaxe générale est [début:fin:pas], où début est l’indice de départ
(inclus), fin l’indice de fin (exclus) et pas l’intervalle entre les éléments. Si ces valeurs sont omises,
NumPy utilise des valeurs par défaut : 0 pour début, la fin du tableau pour fin et 1 pour pas.
Dans une matrice, le slicing s’applique à chaque dimension. Par exemple, pour extraire la première
Ici, : signifie « tous les éléments » pour la dimension des colonnes. La syntaxe a[i, :] renvoie la
ligne d’indice i et a[: ,j] renvoie la colonne d’indice j.
Pour extraire une sous-matrice des deux premières lignes et des deux premières colonnes :
>>> sous_matrice = matrice[0:2, 0:2]
>>> print(sous_matrice)
[[1 2]
[4 5]]
Le slicing permet également de modifier des parties d’un tableau, car les sous-tableaux extraits
par slicing sont des vues du tableau original et non des copies. Cela signifie que modifier un
sous-tableau affecte le tableau d’origine. Par exemple, pour augmenter de 10 la première colonne
d’une matrice :
>>> matrice[:, 0] = matrice[:, 0] + 10
>>> print(matrice)
[[11 2 3]
[14 5 6]]
Cette modification est directe et efficace, mais elle nécessite de la prudence pour éviter des
changements involontaires.
Note. Comme pour les listes, nous attirons votre attention sur la copie de arrays (tableaux). Par
défaut la copie d’arrays se fait par référence, comme pour tous les conteneurs en Python (listes,
tuples, dictionnaires, etc.). Afin d’éviter le problème, vous pouvez soit utiliser la fonction np.
array(), qui crée une nouvelle copie distincte de l’array initial, soit la fonction [Link](),
comme pour les listes.
>>> a = [Link]((2, 2), int)
>>> print(a)
[[0 0]
[0 0]]
>>> b = [Link](a)
>>> b[1, 1] = 100
>>> print(b)
[[ 0 0]
[ 0 100]]
>>> import copy
>>> c = [Link](a)
>>> c[1, 1] = 200
>>> print(c)
[[ 0 0]
[ 0 200]]
>>> print(a)
[[0 0]
[0 0]]
Les masques logiques permettent de filtrer les éléments d’un tableau en fonction de conditions
booléennes, une technique utile pour analyser des données, comme extraire des valeurs dépassant
un seuil. Un masque logique est un tableau de même forme que le tableau d’origine, contenant des
valeurs True ou False selon qu’une condition est satisfaite.
Soit un tableau de températures et une condition pour identifier les valeurs supérieures à 20 degrés :
>>> temperatures = [Link]([20.5, 19.5, 21.0, 19.8, 22.3])
>>> masque = temperatures > 20
>>> print(masque)
[ True False True False True]
Le masque masque contient True pour les éléments satisfaisant la condition temperatures > 20
et False sinon. Vous pouvez utiliser ce masque pour extraire les éléments correspondants :
>>> temp_chaudes = temperatures[masque]
>>> print(temp_chaudes)
[20.5 21. 22.3]
Les masques logiques peuvent être combinés avec des opérateurs logiques comme & (ET), | (OU) et
~(NON). Par exemple, pour sélectionner les températures entre 20 et 21 degrés :
>>> masque = (temperatures >= 20) & (temperatures <= 21)
>>> print(temperatures[masque])
[20.5 21. ]
Notez que les opérateurs logiques and, or et not ne s’appliquent pas sur les arrays.
Les masques logiques permettent également de modifier les éléments sélectionnés. Par exemple,
pour remplacer les températures supérieures à 20 par 20 :
>>> temperatures[temperatures > 20] = 20
>>> print(temperatures)
[20. 19.5 20. 19.8 20. ]
Cette approche est courante dans le traitement des données pour limiter des valeurs aberrantes ou
normaliser des ensembles de données.
Note. Lors de l’utilisation de masques logiques, assurez-vous que les conditions produisent un
tableau booléen de forme compatible. Par ailleurs, placez les conditions combinées entre parenthèses
pour éviter des erreurs de priorité d’opérateurs, comme (condition1) & (condition2).
chaque élément en produisant un nouveau tableau de même forme. Par exemple, la fonction sin
calcule le sinus de chaque élément, ce qui est utile pour analyser des données périodiques, comme
des signaux ou des oscillations. Considérons un tableau représentant des angles en radians :
>>> angles = [Link]([0, [Link]/2, [Link], 3*[Link]/2])
>>> print([Link](angles))
[ 0.0000000e+00 1.0000000e+00 1.2246468e−16 −1.0000000e+00]
Dans cet exemple, [Link] applique la fonction sinus à chaque élément de angles et produit un
tableau où sinus[0] = sin(0) = 0, sinus[1] = sin(π /2) = 1, et ainsi de suite. Le résultat
1.2246468e−16 pour sin(π ) est pratiquement nul, reflétant une approximation numérique due à
la précision des flottants.
NumPy fournit une large gamme de fonctions universelles, couvrant diverses catégories mathéma-
tiques. Vous trouverez la liste complètes dans la documentation officielle de NumPy sur les ufuncs 4 .
Voici les principales catégories avec des exemples représentatifs :
• Fonctions trigonométriques et hyperboliques : sin, cos, tan, arcsin, arccos, arctan,
deg2rad, rad2deg, sinh, cosh, tanh, arcsinh, arccosh, arctanh, etc. Ces fonctions sont
utiles pour analyser des données périodiques ou géométriques. Par exemple, pour convertir
les angles d’un tableau de radians en degrés :
>>> print(np.rad2deg(angles))
[ 0. 90. 180. 270.]
• Fonctions exponentielles et logarithmiques : exp, log, log10, sqrt. Ces fonctions sont
essentielles pour modéliser des phénomènes de croissance ou pour normaliser des données.
Par exemple, pour calculer la racine carrée d’un tableau de distances :
>>> distances = [Link]([4, 9, 16, 25])
>>> print([Link](distances))
[2. 3. 4. 5.]
• Fonctions d’arrondi : round, floor, ceil. Ces fonctions permettent d’ajuster les valeurs
pour simplifier les analyses ou les affichages. Par exemple, pour arrondir des mesures à
l’entier inférieur :
>>> mesures = [Link]([2.7, 3.2, 4.8, 5.1])
>>> print([Link](mesures))
[2. 3. 4. 5.]
Les fonctions universelles sont vectorisées, ce qui signifie qu’elles exploitent l’efficacité des
opérations élément par élément, comme les opérations arithmétiques vues précédemment. Cette
vectorisation élimine le besoin de boucles, rendant le code plus clair et plus performant.
Note. Certaines fonctions universelles, comme log ou sqrt, ne sont définies que pour des valeurs
valides (par exemple, log exige des valeurs positives). Appliquer [Link] à un tableau contenant
des valeurs négatives ou nulles générera une erreur ou des valeurs nan (not a number).
4. [Link]
fonctionnalités puissantes à travers son module d’algèbre linéaire ([Link]) pour manipuler
des matrices et résoudre des problèmes linéaires, ainsi que des fonctions statistiques pour résumer
des données. De plus, le module [Link] permet de générer des données aléatoires, utiles
pour des simulations ou des tests.
L’algèbre linéaire est un pilier des sciences appliquées, permettant de représenter des relations
entre variables à l’aide de matrices et de vecteurs. Le module [Link] propose des fonctions
optimisées pour effectuer des opérations comme le produit matriciel, la transposition, le calcul du
déterminant, l’inversion de matrices, la détermination des valeurs et vecteurs propres et la résolution
de systèmes linéaires.
Le tableau suivant récapitule les principales fonctions d’algèbre linéaire utilisées dans cette section :
Fonction Description
[Link](a, b) Calcule le produit matriciel ou scalaire entre a et b.
[Link](a, b) Effectue le produit matriciel entre a et b, recom-
mandé pour les matrices.
[Link](a) Retourne la transposée de la matrice a.
[Link](a) Calcule le déterminant de la matrice carrée a.
[Link](a) Calcule l’inverse de la matrice carrée non singulière
a.
[Link](a) Retourne les valeurs propres et vecteurs propres de
la matrice carrée a.
[Link](a, b) Résout le système linéaire ax = b, où a est une ma-
trice et b un vecteur.
Produit matriciel : Pour deux matrices A de forme (m, n) et B de forme (n, p), leur produit
matriciel est une matrice de forme (m, p). NumPy propose dot et matmul, matmul étant préféré
pour les matrices à deux dimensions.
Considérons deux matrices 2x2 :
>>> A = [Link]([[1, 2], [3, 4]])
>>> B = [Link]([[5, 6], [7, 8]])
>>> produit = [Link](A, B)
>>> print(produit)
[[19 22]
[43 50]]
Chaque élément du résultat est une somme de produits : par exemple, produit[0,0] = 1*5 +
2*7 = 19. Pour un produit matrice-vecteur ou un produit scalaire :
>>> vecteur = [Link]([5, 9])
>>> print(([Link](A, vecteur)))
[23 51]
>>> print([Link](vecteur, vecteur))
106
Note. Le produit matriciel exige que le nombre de colonnes de A corresponde au nombre de lignes
de B.
Transposée : La transposée d’une matrice A, notée AT , est obtenue en échangeant ses lignes et ses
colonnes : l’élément Ai j devient ATji . NumPy propose la fonction transpose ou l’attribut T :
>>> A = [Link]([[1, 2, 3], [4, 5, 6]])
>>> print([Link](A))
[[1 4]
[2 5]
[3 6]]
>>> print(A.T)
[[1 4]
[2 5]
[3 6]]
Déterminant : Le déterminant d’une matrice carrée est une valeur scalaire qui indique si la matrice
est inversible (déterminant non nul) ou caractérise des propriétés géométriques, comme le facteur
d’échelle d’une transformation. La fonction [Link] calcule le déterminant :
>>> A = [Link]([[1, 2], [3, 4]])
>>> det_A = [Link](A)
>>> print(det_A)
−2.0000000000000004
a b
Pour une matrice 2x2 , le déterminant est a*d − b*c, soit 1*4 − 2*3 = −2. Le résultat est
c d
légèrement inexact en raison de la précision des flottants, mais il est fonctionnellement correct.
Inverses de matrices : L’inverse d’une matrice carrée A est une matrice A_inv telle que A * A_inv
= I, où I est la matrice identité. L’inverse est utilisé pour résoudre des systèmes linéaires ou
inverser des transformations. La fonction [Link] calcule cet inverse :
>>> A = [Link]([[1, 2], [3, 4]])
>>> A_inv = [Link](A)
>>> print(A_inv)
[[−2. 1. ]
[ 1.5 −0.5]]
Vecteurs propres et valeurs propres : Les valeurs propres (λ ) et vecteurs propres (v) d’une
matrice carrée A satisfont A.v = λ .v. La fonction [Link] retourne un tuple contenant les
valeurs propres et les vecteurs propres :
>>> A = [Link]([[1, 2], [2, 1]])
>>> valeurs_propres, vecteurs_propres = [Link](A)
>>> print(valeurs_propres)
[ 3. −1.]
>>> print(vecteurs_propres)
[[ 0.70710678 −0.70710678]
[ 0.70710678 0.70710678]]
Chaque colonne de vecteurs_propres est un vecteur propre associé à la valeur propre correspon-
dante. Par exemple, le premier vecteur propre [0.707, 0.707] correspond à λ = 3.
Systèmes linéaires : Un système d’équations linéaires ax = b peut être résolu avec [Link]
qui est plus efficace que l’inversion explicite. Pour le système :
(
x + 2y = 5
3x + 4y = 11
Les analyses statistiques permettent de résumer et d’interpréter des ensembles de données, comme
des mesures expérimentales ou des observations. NumPy offre des fonctions intégrées pour calculer
des mesures statistiques courantes, telles que la moyenne, l’écart-type, la médiane et d’autres,
appliquées directement aux tableaux ndarray. Ces fonctions sont vectorisées, ce qui les rend
rapides et faciles à utiliser.
Soit un tableau représentant des mesures de température :
1 temperatures = [Link]([20.5, 21.0, 19.8, 22.3, 20.1])
Écart-type : La fonction std mesure la dispersion des données par rapport à la moyenne :
>>> print([Link](temperatures))
0.8777243302996675
Médiane : La fonction median retourne la valeur centrale après tri des données, utile pour des
données avec des valeurs aberrantes :
>>> print([Link](temperatures))
20.5
Minimum et maximum : Les fonctions min et max identifient les valeurs extrêmes :
>>> minimum = [Link](temperatures)
>>> maximum = [Link](temperatures)
>>> print(minimum, maximum)
19.8 22.3
Ces fonctions peuvent être appliquées à des matrices, soit sur l’ensemble des éléments, soit le long
d’un axe spécifique. Par exemple, pour calculer la moyenne de chaque colonne ou de chaque ligne
d’une matrice :
>>> matrice = [Link]([[1, 2, 3], [4, 5, 6]])
>>> moyennes_colonnes = [Link](matrice, axis=0)
>>> print(moyennes_colonnes)
[2.5 3.5 4.5]
>>> moyennes_lignes = [Link](matrice, axis=1)
>>> print(moyennes_lignes)
[2. 5.]
Note. Lors de l’utilisation de fonctions statistiques sur des matrices, spécifiez l’axe (axis) si vous
voulez des résultats par ligne ou colonne. Sans axis, NumPy applique l’opération à tous les éléments,
ce qui peut ne pas correspondre à votre intention. Dans l’exemple précédent, si l’axe n’était pas
spécifié, on aurait eu :
>>> print([Link](matrice))
3.5
Le module [Link] permet de générer des nombres aléatoires, une fonctionnalité essentielle
pour des simulations, des tests statistiques ou la création de données synthétiques. Elles sont utiles
pour modéliser des phénomènes aléatoires, comme le bruit dans des mesures ou la variabilité dans
des expériences.
Les fonctions de [Link] se divisent en deux catégories : les générateurs simples qui
produisent des nombres aléatoires selon des distributions uniformes ou normales et les fonctions de
distributions statistiques qui modélisent des processus spécifiques. Pour garantir la reproductibilité
des résultats, vous pouvez fixer une graine aléatoire avec [Link] :
1 [Link](42)
Le tableau suivant récapitule les principales fonctions de génération aléatoire et les distributions
statistiques disponibles dans [Link] :
Fonction Description
rand(d0, d1, ..., dN) Génère un tableau, de dimension (d0, d1, ...,
dN), de nombres aléatoires uniformément distribués
entre 0 et 1.
randn(d0, d1, ..., dN) Génère un tableau, de dimension (d0, d1, ...,
dN), de nombres suivant une distribution normale
standard (moyenne 0, écart-type 1).
randint(low, high, size) Génère des entiers aléatoires entre low (inclus) et
high (exclus).
choice(a, size, replace) Sélectionne size éléments aléatoires dans a, avec ou
sans remplacement. Par défaut, replace=True.
uniform(low, high, size) Génère des nombres suivant une distribution uni-
forme entre low et high. Par défaut, low=0.0 et high
=1.0.
normal(loc, scale, size) Génère des nombres suivant une distribution normale
avec moyenne loc et écart-type scale. Par défaut,
loc=0.0 et scale=1.0.
poisson(lam, size) Génère des nombres suivant une distribution de Pois-
son avec paramètre lam (taux moyen d’événements).
Par défaut, lam=1.0.
binomial(n, p, size) Génère des nombres suivant une distribution bino-
miale avec n essais et probabilité p.
exponential(scale, size) Génère des nombres suivant une distribution expo-
nentielle avec échelle scale (inverse du taux). Par
défaut, scale=1.0.
Voici quelques exemples d’utilisation. Pour générer un tableau 2x3 de nombres aléatoires uniformes
entre 0 et 1 :
>>> print([Link](2, 3))
[[0.37454012 0.95071431 0.73199394]
[0.59865848 0.15601864 0.15599452]]
Pour simuler des données suivant une distribution normale avec une moyenne de 10 et un écart-type
de 2 :
>>> print([Link](loc=10, scale=2, size=4))
[10.99342831 9.7234714 11.29537708 13.04605971]
Pour modéliser le nombre d’événements dans un processus de Poisson (comme le nombre d’appels
reçus par un centre d’appels en une heure, avec un taux moyen de 5) :
>>> print([Link](lam=5, size=3))
[5 4 4]
Matplotlib est une bibliothèque open-source puissante pour la visualisation de données en Python,
largement utilisée dans les domaines scientifiques et techniques 5 . Elle permet de créer des gra-
phiques variés, tels que des courbes, des diagrammes de dispersion, des histogrammes, et bien plus
encore. Le module pyplot, inclus dans Matplotlib, est l’interface principale pour les utilisateurs
débutants, car il offre une syntaxe simple et intuitive inspirée des commandes de tracé de MATLAB.
Pour utiliser Matplotlib, vous devez d’abord l’importer, généralement avec NumPy pour manipuler
les données. Une convention courante est d’importer pyplot sous l’alias plt :
1 import numpy as np
2 import [Link] as plt
Le module pyplot fournit des fonctions comme plot, scatter ou show qui permettent de tracer
des données et d’afficher les graphiques. Par exemple, la fonction plot crée une courbe en reliant
des points, tandis que show affiche la figure à l’écran. Dans un environnement interactif, comme
Jupyter Notebook, l’affichage peut être automatique, mais dans un script Python, [Link]() est
souvent nécessaire.
Pour préparer un tracé, vous commencez généralement par générer des données avec NumPy. Par
exemple, pour créer un tableau de points représentant une fonction linéaire y = 2x + 1, vous pouvez
utiliser [Link] pour générer des valeurs de x :
1 x = [Link](0, 10, 100) # 100 points de 0 à 10
2 y = 2 * x + 1
Ces données seront ensuite utilisées pour tracer un graphique. Matplotlib est conçu pour être
flexible : vous pouvez travailler dans un style procédural (en appelant des fonctions de pyplot) ou
orienté objet (en manipulant directement les objets Figure et Axes), ce dernier étant introduit plus
loin.
Note. Assurez-vous que Matplotlib est installé dans votre environnement Python. Si ce n’est
pas le cas, vous pouvez l’installer avec la commande pip install matplotlib dans un terminal
avant d’exécuter votre code.
Créer un graphique simple avec Matplotlib est une tâche très accessible. L’objectif est de tracer
une courbe à partir de données, comme une fonction mathématique ou une série de mesures en
utilisant pyplot.
Supposons qu’on a mesuré des températures à différents moments. On peut utiliser un tracé linéaire
pour observer leur évolution :
1 import numpy as np
2 import [Link] as plt
3
4 temps = [Link]([0, 1, 2, 3, 4])
5 temperatures = [Link]([20.5, 21.0, 20.8, 22.0, 21.5])
6 [Link](temps, temperatures)
7 [Link]()
22.0
21.8
21.6
21.4
21.2
21.0
20.8
20.6
7 [Link]()
22.0
21.8
21.6
21.4
21.2
21.0
20.8
20.6
Note. Les données passées à [Link] doivent avoir des formes compatibles. Par exemple, x et y
doivent avoir la même longueur (même nombre d’éléments).
Un graphique Matplotlib est plus qu’une simple courbe : il est composé d’objets hiérarchiques qui
définissent son apparence et son organisation. Comprendre cette structure est essentiel pour maîtriser
Matplotlib, surtout lorsque vous souhaiterez créer des visualisations complexes. Imaginez un
graphique comme une peinture : la toile est la figure, le cadre délimite la zone de dessin (les axes),
et les lignes ou points sont les tracés. Cette sous-sous-section détaille ces composants : Figure,
Axes, et Plot.
• Figure : La Figure est l’objet global qui contient l’ensemble du graphique, comme une
toile vierge. Elle est créée explicitement avec [Link]() ou implicitement par [Link].
Vous pouvez spécifier sa taille avec le paramètre figsize (en pouces).
• Axes : Un objet Axes (à ne pas confondre avec les axes x et y) est une zone de la figure où les
données sont tracées, comme un cadre contenant une courbe ou un diagramme. Une figure
peut contenir plusieurs Axes (par exemple, pour des sous-graphiques). Chaque Axes a ses
propres axes x et y, étiquettes et tracés.
• Plot : Le Plot désigne les éléments visuels, comme des lignes, des points ou des barres,
tracés dans un Axes. Il est créé avec des fonctions comme plot ou scatter.
Pour illustrer, considérons un graphique simple créé en style orienté objet, qui rend la structure
explicite :
1 import numpy as np
2 import [Link] as plt
3
4 # Création de la figure
22.0
21.8
21.6
21.4
21.2
21.0
20.8
20.6
Lors de la création d’un graphique avec [Link], Matplotlib applique des styles par défaut,
comme une ligne bleue continue. Cependant, vous pouvez personnaliser ces styles pour améliorer
la lisibilité ou distinguer plusieurs tracés. Les principaux paramètres de style sont les couleurs, les
types de lignes et les marqueurs, qui sont spécifiés dans la fonction plot via des arguments comme
color, linestyle et marker.
Couleurs : Les couleurs peuvent être définies par des noms (par exemple, blue, red, green), des
codes hexadécimaux (par exemple, #FF0000 pour le rouge) ou des abréviations (par exemple, b
pour bleu, r pour rouge). Par exemple, pour tracer une droite rouge :
1 import numpy as np
2 import [Link] as plt
3
4 x = [Link](0, 10, 10)
5 y = 2 * x + 1
6 [Link](x, y, color='red')
7 [Link]()
Ce code génère une droite rouge reliant les points (xi , yi ). Vous pouvez également utiliser c comme
alias pour color, par exemple, c='r'.
20.0
17.5
15.0
12.5
10.0
7.5
5.0
2.5
0.0
0 2 4 6 8 10
Types de lignes : Le paramètre linestyle contrôle l’apparence de la ligne : continue (−), pointillée
(−−), tirets-points (−.) ou points (:). Par exemple, pour une ligne pointillée :
1 import numpy as np
2 import [Link] as plt
3
4 x = [Link](0, 10, 10)
5 y = 2 * x + 1
6 [Link](x, y, linestyle='−−', color='blue')
7 [Link]()
Ce graphique affiche la même droite, mais avec une ligne bleue pointillée, rendant le tracé visuelle-
ment distinct.
20.0
17.5
15.0
12.5
10.0
7.5
5.0
2.5
0.0
0 2 4 6 8 10
F IGURE 7.5 – Droite linéaire y = 2x + 1 tracée avec une ligne bleue pointillée.
Marqueurs : Les marqueurs permettent d’afficher les points de données individuels, utiles pour les
diagrammes de dispersion ou pour mettre en évidence des points spécifiques sur une courbe. Les
options sont des cercles (o), des carrés (s), des triangles (^) ou des étoiles (*). Par exemple, pour
ajouter des marqueurs circulaires :
1 import numpy as np
2 import [Link] as plt
3
4 x = [Link](0, 10, 20)
5 y = 2 * x + 1
6 [Link](x, y, marker='o', linestyle='−', color='green')
7 [Link]()
Ce code trace une droite verte continue, avec un cercle vert à chaque point de donnée.
Pour un graphique de dispersion sans lignes, omettez linestyle ou utilisez linestyle='' :
1 x = [Link]([1, 2, 3, 4])
2 y = [Link]([2, 4, 1, 5])
3 [Link](x, y, marker='s', linestyle='', color='purple')
4 [Link]()
Ce graphique affiche quatre carrés violets aux coordonnées (1, 2), (2, 4), (3, 1), et (4, 5), sans lignes
de connexion.
Vous pouvez combiner ces options dans une chaîne de formatage concise. Par exemple, 'r−−o'
signifie une ligne rouge pointillée avec des marqueurs circulaires :
1 x = [Link](0, 10, 20) # Moins de points pour voir les marqueurs
2 y = [Link](x)
20.0
17.5
15.0
12.5
10.0
7.5
5.0
2.5
0.0
0 2 4 6 8 10
F IGURE 7.6 – Droite linéaire y = 2x + 1 tracée en vert avec des marqueurs circulaires.
5.0
4.5
4.0
3.5
3.0
2.5
2.0
1.5
1.0
1.0 1.5 2.0 2.5 3.0 3.5 4.0
3 [Link](x, y, 'r−−o')
4 [Link]()
Ce code produit une courbe sinusoidale rouge pointillée, avec des cercles rouges aux 20 points de
donnée, oscillant entre −1 et 1.
1.00
0.75
0.50
0.25
0.00
0.25
0.50
0.75
1.00
0 2 4 6 8 10
F IGURE 7.8 – Courbe sinusoidale tracée en rouge pointillé avec des marqueurs circulaires.
Note. Lorsque vous utilisez des marqueurs, choisissez un nombre raisonnable de points avec
[Link] (par exemple, 20 au lieu de 100) pour éviter que les marqueurs ne se chevauchent,
rendant le graphique illisible.
Ces options de style vous permettent de différencier les tracés, par exemple, pour comparer plusieurs
courbes dans un même graphique.
Un graphique doit inclure des annotations pour expliquer son contenu et faciliter son interprétation.
Matplotlib permet d’ajouter des étiquettes aux axes (xlabel, ylabel), un titre (title), et une lé-
gende (legend) pour identifier les tracés. Ces éléments sont cruciaux pour rendre vos visualisations
communicatives, que ce soit dans un rapport ou une présentation.
Pour qu’un graphique soit informatif, il doit inclure des annotations pour expliquer son contenu et
faciliter son interprétation. Matplotlib permet d’ajouter des étiquettes aux axes (xlabel, ylabel),
un titre (title) et une légende (legend) pour identifier les tracés.
Considérez un graphique comparant deux fonctions : y = sin(x) et y = cos(x). Vous pouvez ajouter
des labels, un titre et une légende pour clarifier le contenu :
1 import numpy as np
2 import [Link] as plt
3
4 x = [Link](0, 2 * [Link], 100)
5 y1 = [Link](x)
6 y2 = [Link](x)
7
8 [Link](x, y1, 'b−', label='sin(x)')
9 [Link](x, y2, 'r−−', label='cos(x)')
10 [Link]('x (radians)')
11 [Link]('Valeur')
12 [Link]('Comparaison de sin(x) et cos(x)')
13 [Link]()
14 [Link]()
Ce code produit un graphique avec deux courbes : une courbe bleue continue pour sin(x) et une
courbe rouge pointillée pour cos(x). Les annotations sont :
• xlabel('x (radians)') : étiquette l’axe des x comme représentant des angles en radians.
• ylabel('Valeur') : indique que l’axe des y représente les valeurs des fonctions.
• title('Comparaison de sin(x) et cos(x)') : donne un titre descriptif au graphique.
• legend() : affiche une légende identifiant chaque courbe, utilisant les labels spécifiés dans
[Link] ('sin(x)' et 'cos(x)').
• grid() : affiche une grille.
Le résultat est un graphique clair montrant les courbes oscillant entre −1 et 1. Vous pouvez contrôler
la position de la légende avec l’argument loc, par exemple, loc='lower right' pour la placer en
bas à droite.
0.00
0.25
0.50
0.75
sin(x)
1.00 cos(x)
0 1 2 3 4 5 6
x (radians)
F IGURE 7.9 – Comparaison des fonctions sin(x) et cos(x) avec étiquettes et légende.
Pour un autre exemple, supposons qu’on visualise des données de température à deux moments de
la journée :
1 jours = [Link]([1, 2, 3, 4, 5])
2 matin = [Link]([15.5, 16.0, 14.8, 15.2, 16.5])
3 soir = [Link]([20.5, 21.0, 19.8, 20.2, 21.5])
4
5 [Link](jours, matin, 'bo−', label='Matin')
6 [Link](jours, soir, 'rs−−', label='Soir')
7 [Link]('Jour')
8 [Link]('Température (°C)')
9 [Link]('Températures quotidiennes')
10 [Link]()
11 [Link]()
Ce graphique montre deux courbes : une ligne bleue continue avec des cercles pour les températures
du matin et une ligne rouge pointillée avec des carrés pour celles du soir. Les étiquettes et la légende
rendent le graphique immédiatement compréhensible, avec l’axe des x indiquant les jours et l’axe
des y les températures en degrés Celsius.
Températures quotidiennes
21
20
Température (°C)
19
18
17
16
Matin
15 Soir
1.0 1.5 2.0 2.5 3.0 3.5 4.0 4.5 5.0
Jour
Note. Assurez-vous que chaque tracé dans un graphique avec légende a un label défini dans
[Link]. Sans label, [Link]() peut générer une erreur ou omettre des tracés.
Ces annotations transforment un graphique brut en une visualisation communicative, adaptée à une
analyse ou une présentation.
Les échelles et limites des axes influencent la manière dont les données sont représentées. Matplotlib
permet de modifier l’échelle des axes (linéaire ou logarithmique) avec set_xscale et set_yscale
et de définir des limites avec set_xlim et set_ylim. Ces ajustements sont essentiels pour mettre
en évidence des tendances ou zoomer sur une région spécifique.
Échelles des axes : Par défaut, Matplotlib utilise une échelle linéaire, où les intervalles sont
proportionnels aux valeurs. Cependant, pour des données couvrant plusieurs ordres de grandeur
(par exemple, des populations ou des fréquences), une échelle logarithmique est plus appropriée.
Considérez une fonction exponentielle y = ex :
1 import numpy as np
2 import [Link] as plt
3
4 x = [Link](0, 5, 100)
5 y = [Link](x)
6
7 fig, ax = [Link]()
8 [Link](x, y)
9 ax.set_yscale('log')
10 ax.set_xlabel('x')
11 ax.set_ylabel('exp(x)')
12 ax.set_title('Exponentielle avec échelle logarithmique')
13 [Link]()
Ce graphique utilise une échelle logarithmique sur l’axe des y, transformant la courbe exponentielle
en une droite, car log(ex ) = x.
102
exp(x)
101
100
0 1 2 3 4 5
x
F IGURE 7.11 – Fonction exponentielle y = ex avec une échelle logarithmique sur l’axe des y.
Vous pouvez également appliquer une échelle logarithmique à l’axe des x avec ax.set_xscale('
log'), utile pour des données comme des fréquences ou des échelles temporelles.
Limites des axes : Les limites des axes contrôlent la plage de valeurs affichée. Par exemple, pour
une courbe sinus :
1 x = [Link](0, 2 * [Link], 100)
2 y = [Link](x)
3
4 fig, ax = [Link]()
5 [Link](x, y)
6 ax.set_xlim(0, [Link])
7 ax.set_ylim(−0.5, 1)
8 ax.set_xlabel('x (radians)')
9 ax.set_ylabel('sin(x)')
10 ax.set_title('Sinus avec limites ajustées')
11 [Link]()
Ce graphique affiche seulement la moitié de la période du sinus (de 0 à π), avec l’axe des y limité à
[−0.5, 1], mettant en évidence la montée de la courbe. Le résultat est une courbe bleue continue,
0.8
0.6
0.4
sin(x)
0.2
0.0
0.2
0.4
0.0 0.5 1.0 1.5 2.0 2.5 3.0
x (radians)
Note. Lors de l’ajustement des limites avec set_xlim ou set_ylim, assurez-vous que les valeurs
sont cohérentes avec les données. Par exemple, définir set_ylim(0, 0) ou des limites en dehors
des données peut produire un graphique vide ou trompeur.
Pour faciliter la personnalisation de vos graphiques, les tableaux suivants récapitulent les principales
options de style et de configuration disponibles dans Matplotlib. Ces tableaux constituent une
référence rapide pour choisir les marqueurs, types de lignes, couleurs et positions de légendes, vous
permettant de créer des visualisations adaptées à vos besoins. Consultez ces tableaux lorsque vous
concevez vos graphiques pour sélectionner les options les plus appropriées.
Marqueur Description
o Cercle
s Carré
^ Triangle pointant vers le haut
v Triangle pointant vers le bas
* Étoile
+ Croix
x X
d Losange
Ces tableaux regroupent les options les plus courantes pour personnaliser vos graphiques. Pour des
options supplémentaires, comme des tailles de marqueurs ou des épaisseurs de lignes, référez-vous
à la documentation officielle de Matplotlib 6 .
6. [Link]
Option Description
− Ligne continue
−− Ligne pointillée
−. Ligne avec tirets et points
: Ligne en points
Option Description
blue, b Couleur bleu
red, r Couleur rouge
green, g Couleur verte
purple, p Couleur violette
cyan, c Couleur cyan
magenta, m Couleur magenta
yellow, y Couleur jaune
black, k Couleur noire
white, w Couleur blanche
#FF0000 Rouge (code hexadécimal)
#00FF00 Vert (code hexadécimal)
#0000FF Bleu (code hexadécimal)
Ce tableau vous servira de guide pour choisir le graphique adapté à vos données. Les sections
suivantes détaillent les tracés linéaires, les diagrammes de dispersion et les histogrammes, avec des
exemples concrets pour vous familiariser avec leur création.
Les tracés linéaires, créés avec la fonction plot, permettent de représenter des données continues,
comme des séries temporelles, des fonctions mathématiques ou des mesures évoluant progressive-
ment. En reliant les points par des lignes, ces graphiques permettent de visualiser des tendances
ou des variations. Vous avez déjà utilisé [Link] dans les sections précédentes pour tracer des
fonctions comme sin(x).
Considérons une série temporelle représentant la consommation d’énergie quotidienne d’un bâti-
ment sur une semaine :
1 import numpy as np
2 import [Link] as plt
3
4 jours = [Link]([1, 2, 3, 4, 5, 6, 7])
5 consommation = [Link]([120, 115, 130, 125, 140, 135, 128])
6
7 [Link](jours, consommation, 'b−o', label='Consommation (kWh)')
8 [Link]('Jour')
9 [Link]('Consommation (kWh)')
10 [Link]('Consommation d'énergie quotidienne')
11 [Link]()
12 [Link]()
13 [Link]()
Ce code génère un graphique avec une ligne bleue continue reliant sept points marqués par des
cercles, représentant la consommation d’énergie de 120 à 140 kWh sur une semaine. Les étiquettes
et la légende rendent le graphique clair, avec l’axe des x indiquant les jours et l’axe des y la
consommation en kilowattheures.
135
Consommation (kWh)
130
125
120
115
1 2 3 4 5 6 7
Jour
Note. Pour les tracés linéaires, assurez-vous que les données sont ordonnées selon l’axe des x si
vous représentez une séquence temporelle ou une relation continue. Des données désordonnées
peuvent produire des lignes en zigzag déroutantes.
Les tracés linéaires sont polyvalents et constituent un outil de base pour explorer des tendances
dans vos données, que ce soit pour des mesures réelles ou des modèles théoriques.
Les diagrammes de dispersion, créés avec la fonction scatter, affichent des points individuels
(nuages de points) pour visualiser les relations entre deux variables, sans les relier par des lignes.
Ils sont utiles pour analyser des corrélations, identifier des regroupements ou repérer des valeurs
aberrantes dans des données expérimentales. Contrairement à plot avec linestyle='', scatter
offre plus de contrôle sur la taille, la couleur et la forme des points.
Supposons que l’on étudie la relation entre la température et la consommation d’énergie dans un
bâtiment :
1 import numpy as np
2 import [Link] as plt
3
4 temperatures = [Link]([15, 16, 14, 17, 18, 16, 15])
5 consommation = [Link]([130, 125, 135, 120, 115, 128, 132])
6
Ce code produit un diagramme de dispersion avec des cercles violets de taille 100 (spécifiée par
s=100) aux coordonnées (tempratures[i], consommation[i]). Le graphique suggère une possible
corrélation négative : la consommation diminue légèrement lorsque la température augmente.
127.5
125.0
122.5
120.0
117.5
115.0
14.0 14.5 15.0 15.5 16.0 16.5 17.0 17.5 18.0
Température (°C)
Pour un exemple plus complexe, visualisons des données bidimensionnelles avec des couleurs
variables pour indiquer une troisième variable, comme la pression atmosphérique :
1 [Link](42)
2 temperatures = [Link](10, 20, 10)
3 consommation = [Link](100, 150, 10)
4 pression = [Link](900, 1100, 10)
5
6 scatter = [Link](temperatures, consommation, c=pression, s=150, cmap='
viridis', label='Données')
7 [Link](label='Pression (hPa)')
8 [Link]('Température (°C)')
9 [Link]('Consommation (kWh)')
10 [Link]('Température vs Consommation avec pression')
11 [Link]()
12 [Link]()
Ce graphique affiche 10 points, dont la couleur varie selon la pression (de 900 à 1100 hPa), utilisant
la colormap viridis. Une barre de couleur indique l’échelle de pression, rendant le graphique
informatif sur trois variables.
130 1000
Pression (hPa)
980
120
960
110 940
920
100
12 14 16 18
Température (°C)
Note. Lors de l’utilisation de scatter, vérifiez que les tableaux x et y ont la même longueur et
que les paramètres comme s (taille) ou c (couleur) sont cohérents avec les données pour éviter des
erreurs.
[Link] Histogrammes
Les histogrammes, créés avec la fonction hist, visualisent la distribution des données en regroupant
les valeurs dans des intervalles (ou « bacs ») et en affichant leur fréquence sous forme de barres.
Ils sont essentiels pour analyser la répartition des données, comme la fréquence des mesures ou la
forme d’une distribution. Les histogrammes sont adaptés aux données continues ou aux résultats
d’expériences.
Soit un ensemble de mesures de température collectées sur un mois :
1 import numpy as np
2 import [Link] as plt
3
4 temperatures = [Link](20, 2, 1000) # Moyenne 20°C, écart−type 2°C
5
6 [Link](temperatures, bins=20, color='skyblue', edgecolor='black', label='
Températures')
7 [Link]('Température (°C)')
8 [Link]('Fréquence')
9 [Link]('Distribution des températures')
10 [Link]()
11 [Link]()
150
125
Fréquence
100
75
50
25
0
10.0 12.5 15.0 17.5 20.0 22.5 25.0
Température (°C)
F IGURE 7.16 – Histogramme de la distribution des températures suivant une loi normale.
Note. Le choix du nombre de bacs (bins) est crucial pour les histogrammes. Trop peu de bacs
peuvent masquer des détails, tandis que trop de bacs peuvent rendre le graphique bruité. Expéri-
√
mentez avec différentes valeurs ou utilisez une règle comme n (où n est le nombre de données)
pour un compromis.
Les sous-graphiques (ou subplots) sont des graphiques individuels disposés dans une grille au sein
d’une même figure. La fonction [Link] est l’outil principal pour créer ces sous-graphiques,
permettant de définir le nombre de lignes et de colonnes de la grille. Chaque sous-graphique est un
objet Axes, que vous pouvez personnaliser indépendamment, comme expliqué dans la sous-section
sur la structure des figures.
Pour illustrer, créez une figure avec deux sous-graphiques côte à côte pour comparer les fonctions
sin(x) et cos(x) :
1 import numpy as np
2 import [Link] as plt
3
4 x = [Link](0, 2 * [Link], 100)
5 y1 = [Link](x)
6 y2 = [Link](x)
7
Ce code génère une figure de taille 10 pouces par 4 pouces contenant deux sous-graphiques
horizontaux. Le premier (ax1) montre une courbe bleue continue pour sin(x) et le second (ax2)
une courbe rouge pointillée pour cos(x). Chaque sous-graphique a ses propres étiquettes, titre et
légende.
Sinus Cosinus
1.00 sin(x) 1.00
0.75 0.75
0.50 0.50
0.25 0.25
Valeur
Valeur
0.00 0.00
0.25 0.25
0.50 0.50
0.75 0.75
Note. Lors de la création de sous-graphiques, vérifiez que la taille de la figure (figsize) est
adaptée au nombre de sous-graphiques pour éviter des graphiques trop petits ou des étiquettes
illisibles. Utilisez tight_layout pour optimiser l’espacement.
Lorsque vous comparez des sous-graphiques, il est souvent utile de synchroniser leurs échelles
d’axes pour faciliter les comparaisons visuelles. [Link] permet de partager les axes x ou
y entre sous-graphiques avec les arguments sharex et sharey. De plus, des personnalisations
globales, comme un titre principal ou un ajustement de l’espacement, peuvent être appliquées à la
figure entière.
Soit une figure avec quatre sous-graphiques comparant des fonctions trigonométriques (sin(x),
cos(x), sin(2x), cos(2x)) avec des axes y partagés :
1 import numpy as np
2 import [Link] as plt
3
4 x = [Link](0, 2 * [Link], 100)
5 y1 = [Link](x)
6 y2 = [Link](x)
7 y3 = [Link](2 * x)
8 y4 = [Link](2 * x)
9
10 fig, axs = [Link](2, 2, figsize=(10, 8), sharey=True)
11
12 axs[0, 0].plot(x, y1, 'b−', label='sin(x)')
13 axs[0, 0].set_title('Sinus')
14 axs[0, 0].legend()
15
16 axs[0, 1].plot(x, y2, 'r−−', label='cos(x)')
17 axs[0, 1].set_title('Cosinus')
18 axs[0, 1].legend()
19
20 axs[1, 0].plot(x, y3, 'g−', label='sin(2x)')
21 axs[1, 0].set_title('Sinus double')
22 axs[1, 0].legend()
23
24 axs[1, 1].plot(x, y4, 'm−−', label='cos(2x)')
25 axs[1, 1].set_title('Cosinus double')
26 axs[1, 1].legend()
27
28 for ax in [Link]:
29 ax.set_xlabel('x (radians)')
30 ax.set_ylabel('Valeur')
31
32 [Link]('Comparaison des fonctions trigonométriques', fontsize=16)
33 plt.tight_layout()
34 fig.subplots_adjust(top=0.9) # Ajuste pour le titre principal
35 [Link]()
Ce code crée une grille 2x2 de sous-graphiques, avec une taille de figure de 10 pouces par 8 pouces.
L’argument sharey=True synchronise l’échelle des axes y et fixe la plage à [−1, 1] pour toutes les
courbes.
Chaque sous-graphique a un titre et une légende et les étiquettes d’axes sont appliquées via une
boucle sur [Link]. La fonction suptitle ajoute un titre principal à la figure et subplots_adjust
réserve de l’espace pour éviter le chevauchement avec les sous-titres.
Comparaison des fonctions trigonométriques
Sinus Cosinus
1.0
sin(x)
0.5
0.0
Valeur
Valeur
0.5
1.0 cos(x)
1 0 1 2 3 4 5 0 1 2 3 4 5 6
x (radians) x (radians)
Sinus double Cosinus double
1.0
sin(2x)
0.5
0.0
Valeur
Valeur
0.5
1.0 cos(2x)
0 1 2 3 4 5 6 0 1 2 3 4 5 6
x (radians) x (radians)
Pour un autre exemple, visualisons des histogrammes de différentes distributions avec des axes y
partagés pour comparer les fréquences :
1 import numpy as np
2 import [Link] as plt
3
4 [Link](42)
5 data1 = [Link](0, 1, 1000) # Normale standard
6 data2 = [Link](2, 1.5, 1000) # Moyenne 2, écart−type 1.5
7
8 fig, (ax1, ax2) = [Link](1, 2, figsize=(12, 5), sharey=True)
9
10 [Link](data1, bins=20, color='skyblue', edgecolor='black', label='Normale
(mu=0, sigma=1)')
11 ax1.set_xlabel('Valeur')
12 ax1.set_ylabel('Fréquence')
13 ax1.set_title('Distribution normale standard')
14 [Link]()
15
16 [Link](data2, bins=20, color='salmon', edgecolor='black', label='Normale (
mu=2, sigma=1.5)')
17 ax2.set_xlabel('Valeur')
18 ax2.set_ylabel('Fréquence')
19 ax2.set_title('Distribution normale décalée')
20 [Link]()
21
22 [Link]('Comparaison des distributions normales', fontsize=16)
23 plt.tight_layout()
24 fig.subplots_adjust(top=0.85)
25 [Link]()
Ce code génère deux histogrammes côte à côte dans une figure de 12 pouces par 5 pouces.
L’argument sharey=True synchronise l’axe des y, facilitant la comparaison des fréquences. Le
premier histogramme (bleu clair) montre une distribution normale centrée à 0, et le second (saumon)
une distribution centrée à 2 avec une dispersion plus large. Le titre principal et l’ajustement de
l’espacement (subplots_adjust) assurent une présentation soignée.
120
100
Fréquence
Fréquence
80
60
40
20
0
3 2 1 0 1 2 3 4 2 0 2 4 6
Valeur Valeur
Note. Lorsque vous partagez des axes avec sharex ou sharey, les limites et échelles sont syn-
chronisées. Si les données ont des plages très différentes, cela peut rendre certains sous-graphiques
illisibles. Vérifiez les échelles avant de partager.
• PNG : Un format d’image matricielle, idéal pour les présentations ou les documents né-
cessitant une bonne qualité sans perte de détails. Il est compact mais ne permet pas de
redimensionner sans perte de qualité.
• PDF : Un format vectoriel, parfait pour les documents imprimés ou les publications scienti-
fiques, car il conserve la netteté à toutes les échelles. Il est largement utilisé dans les articles
académiques.
• SVG : Un format vectoriel adapté aux graphiques redimensionnables, souvent utilisé pour
les visualisations interactives sur le web ou pour une édition ultérieure dans des logiciels.
Lors de l’exportation d’un graphique avec [Link], vous pouvez ajuster des paramètres pour
contrôler la qualité, la taille et l’apparence du fichier généré. Les paramètres clés incluent dpi
(résolution), bbox_inches (ajustement des marges) et transparent (fond transparent). Ces options
vous permettent d’adapter le graphique à des besoins spécifiques, comme une impression haute
Une Series est une structure de données unidimensionnelle, comparable à une colonne dans une
feuille de calcul ou à une liste Python avec des étiquettes. Chaque élément d’une Series est associé
à un index qui peut être un numéro (par défaut, commençant à 0) ou une étiquette personnalisée
(par exemple, des noms ou des dates). C’est un tableau unidimensionnel contenant des données de
même type (par exemple, entiers, flottants, chaînes) et un index qui identifie chaque élément.
Pour créer une Series, vous pouvez utiliser la fonction [Link] en passant une liste ou un
tableau NumPy. Voici un exemple simple représentant les notes de cinq étudiants :
>>> import pandas as pd
>>> notes = [Link]([15.5, 12.0, 18.0, 9.5, 14.0])
>>> print(notes)
0 15.5
1 12.0
2 18.0
3 9.5
4 14.0
dtype: float64
Ce code crée une Series avec cinq notes, associées à un index par défaut (0 à 4). La sortie
montre les valeurs et leur type (float64), indiquant que les données sont des nombres à virgule
flottante. Vous pouvez accéder à une note spécifique en utilisant l’index, par exemple notes[2] ou
[Link][2] renvoie 18.0.
7. [Link]
8. [Link]
Ici, chaque note est associée à un nom, ce qui facilite l’identification des données. Par exemple,
notes['Claire'] ou [Link]['Claire'] renvoie 18.0. Cela permet de travailler avec des
données étiquetées de manière naturelle, ce qui fait l’une des forces de Pandas.
Note. Lors de la création d’une Series, assurez-vous que la longueur de l’index correspond à celle
des données. Par exemple, fournir cinq valeurs avec seulement quatre étiquettes d’index générera
une erreur.
Les Series sont la base des structures de Pandas. Elles sont souvent utilisées comme composants
des DataFrames.
Un DataFrame est une structure de données bidimensionnelle, comparable à une feuille de calcul
ou une table de base de données, avec des lignes et des colonnes. Chaque colonne d’un DataFrame
est une Series et partage un même index pour les lignes.
Pour illustrer, créons un DataFrame représentant les notes et les matières de trois étudiants :
>>> donnees = {
... 'Nom': ['Alice', 'Bob', 'Claire'],
... 'Maths': [15.5, 12.0, 18.0],
... 'Physique': [14.0, 13.5, 16.5]
... }
>>> df = [Link](donnees)
>>> print(df)
Nom Maths Physique
0 Alice 15.5 14.0
1 Bob 12.0 13.5
2 Claire 18.0 16.5
Ce code crée un DataFrame à partir d’un dictionnaire où chaque clé ('Nom', 'Maths', 'Physique')
devient une colonne et les valeurs forment les lignes. L’index par défaut est 0, 1, 2. La sortie
montre un tableau clair avec les noms des étudiants et leurs notes dans deux matières. Vous pouvez
accéder à une colonne comme une Series, par exemple df['Maths'] ou à une cellule spécifique,
comme df['Maths'][0] pour obtenir 15.5.
Vous pouvez également définir un index personnalisé, par exemple en utilisant la colonne 'Nom' :
>>> df = [Link](donnees).set_index('Nom')
>>> print(df)
Maths Physique
Nom
Alice 15.5 14.0
Ici, la colonne 'Nom' devient l’index, rendant le DataFrame plus intuitif pour identifier les lignes
par nom. Par exemple, [Link]['Alice'] renvoie les notes d’Alice en Maths et Physique.
Note. Lorsque vous créez un DataFrame à partir d’un dictionnaire, assurez-vous que toutes les
listes associées aux clés ont la même longueur. Une incohérence (par exemple, quatre noms mais
trois notes) provoquera une erreur.
Créer des Series et des DataFrames est la première étape pour travailler avec Pandas. Ces struc-
tures peuvent être construites à partir de différentes sources, comme des listes, des dictionnaires ou
des tableaux NumPy. Une fois créées, vous pouvez utiliser des méthodes d’inspection pour explorer
leurs propriétés, comme leur taille, leurs index ou leurs colonnes. Ces outils sont essentiels pour
comprendre vos données avant de les manipuler ou de les analyser.
Création de Series et DataFrames : Vous pouvez créer une Series à partir d’une liste, d’un
dictionnaire ou d’un tableau NumPy. Par exemple, pour une Series à partir d’un dictionnaire :
>>> d = {'Lundi': 20, 'Mardi': 22, 'Mercredi': 19}
>>> temperatures = [Link](d)
>>> print(temperatures)
Lundi 20
Mardi 22
Mercredi 19
dtype: int64
On crée une Series avec des températures associées à des jours comme index. Le type int64
indique des entiers.
Pour un DataFrame, vous pouvez utiliser un dictionnaire de listes, un dictionnaire de Series ou un
tableau NumPy. Voici un exemple avec un tableau NumPy :
>>> data = [Link]([[15, 14], [12, 13], [18, 16]])
>>> df = [Link](data, columns=['Maths', 'Physique'],
... index=['Alice', 'Bob', 'Claire'])
>>> print(df)
Maths Physique
Alice 15 14
Bob 12 13
Claire 18 16
Cela crée un DataFrame à partir d’un tableau NumPy 3x2, avec des colonnes nommées 'Maths'
et 'Physique', et un index basé sur les noms des étudiants. Le résultat est un tableau structuré,
similaire à l’exemple précédent.
Inspection des structures : Pandas fournit des méthodes pour examiner les Series et DataFrames.
Les plus courantes sont head(), tail(), index, columns et shape. Le tableau suivant récapitule
ces méthodes :
Pour illustrer, inspectez le DataFrame précédent :
>>> print([Link](2))
Maths Physique
Méthode Description
head(n) Affiche les n premières lignes (par défaut, 5).
tail(n) Affiche les n dernières lignes (par défaut, 5).
index Retourne l’index de la Series ou du DataFrame.
columns Retourne les noms des colonnes du DataFrame.
shape Retourne un tuple avec le nombre de lignes et de
colonnes.
size Renvoie un entier représentant le nombre d’éléments
de la Series ou du DataFrame.
Alice 15 14
Bob 12 13
>>> print([Link])
Index(['Alice', 'Bob', 'Claire'], dtype='object')
>>> print([Link])
Index(['Maths', 'Physique'], dtype='object')
>>> print([Link])
(3, 2)
>>> print([Link])
6
Les fichiers CSV (Comma-Separated Values) et Excel sont des formats standards pour stocker des
données tabulaires. Un fichier CSV est un fichier texte où chaque ligne représente une observation
et les valeurs sont séparées par des virgules (ou d’autres délimiteurs, comme des points-virgules).
Un fichier Excel, souvent au format .xlsx, organise les données dans des feuilles de calcul, avec
des colonnes et des lignes similaires à un DataFrame. Pandas fournit les fonctions pd.read_csv et
pd.read_excel pour charger ces fichiers directement dans un DataFrame.
Pour commencer, créez un fichier CSV fictif contenant des notes d’étudiants puis lisez-le avec
pd.read_csv. Voici un exemple où on génère d’abord le fichier puis le charge :
1 import pandas as pd
2
3 # Création d'un DataFrame et sauvegarde en CSV
4 donnees = {
5 'Nom': ['Alice', 'Bob', 'Claire', 'David', 'Emma', 'Florent'],
6 'Maths': [15.5, 12.0, 18.0, 9.5, 14.0, 16.0],
7 'Physique': [14.0, 13.5, 16.5, 11.0, 15.0, 10.5]
8 }
9 df = [Link](donnees)
10 df.to_csv('[Link]', index=False)
11
12 # Lecture du fichier CSV
13 df_notes = pd.read_csv('[Link]')
14 print(df_notes)
On commence par créer un DataFrame avec les notes de six étudiants en Maths et Physique puis on
le sauvegarde dans un fichier [Link] sans inclure l’index (index=False), en utilisant la méthode
.to_csv(). Le fichier est enregistré dans le répertoire courant. La fonction pd.read_csv('notes.
csv') charge le fichier dans un nouveau DataFrame, df_notes. La sortie affiche un tableau clair
avec trois colonnes (Nom, Maths, Physique) et six lignes, correspondant aux données initiales.
Chaque colonne est interprétée comme une Series et les types de données sont automatiquement
détectés (float64 pour les notes, object pour les noms).
Note. Lors de la lecture d’un fichier CSV, assurez-vous que le chemin du fichier est correct
(par exemple, '[Link]' si le fichier est dans le répertoire courant). Si le fichier utilise un
délimiteur autre que la virgule, comme un point-virgule, spécifiez-le avec l’argument sep=';' dans
pd.read_csv. Un fichier mal formaté peut provoquer une erreur ou des données mal alignées.
Pour un fichier Excel, l’approche est similaire, mais vous utilisez pd.read_excel. Voici un exemple
où on crée un fichier Excel fictif avec des données météorologiques puis le lit :
1 import pandas as pd
2
3 # Création d'un DataFrame et sauvegarde en Excel
4 meteo = {
5 'Date': ['2023−01−01', '2023−01−02', '2023−01−03', '2023−01−04',
6 '2023−01−05', '2023−01−06', '2023−01−07'],
7 'Température': [5.0, 6.5, 4.0, 7.0, 8.5, 5.5, 6.0],
8 'Précipitations': [0.0, 2.5, 10.0, 0.0, 1.0, 5.0, 3.0]
9 }
10 df_meteo = [Link](meteo)
11 df_meteo.to_excel('[Link]', index=False)
12
13 # Lecture du fichier Excel
14 df_meteo_lu = pd.read_excel('[Link]')
15 print(df_meteo_lu)
Dans cet exemple, on crée un DataFrame avec des données météorologiques sur sept jours (dates,
températures, précipitations), le sauvegarde dans [Link] avec .to_excel(), puis le charge
avec pd.read_excel. La sortie montre un tableau avec trois colonnes et sept lignes, où Date est
interprété comme une chaîne (object) et les autres colonnes comme float64.
Après avoir importé des données dans un DataFrame, il est essentiel d’en obtenir un aperçu pour
comprendre sa structure, ses dimensions et les types de données de ses colonnes. Pandas propose
des méthodes simples, comme head(), tail(), vues précédemment et info() qui permettent
d’examiner rapidement un DataFrame sans avoir à afficher toutes les données, ce qui est utile pour
des ensembles volumineux.
Pour rappel, la méthode head(n) affiche les n premières lignes du DataFrame (par défaut, n=5),
tandis que tail(n) montre les n dernières lignes. Ces méthodes sont idéales pour vérifier si les
données ont été correctement chargées. Par exemple, reprenez le DataFrame des notes :
>>> df_notes = pd.read_csv('[Link]')
>>> print(df_notes.head(3))
Nom Maths Physique
0 Alice 15.5 14.0
1 Bob 12.0 13.5
2 Claire 18.0 16.5
>>> print(df_notes.tail(2))
Nom Maths Physique
4 Emma 14.0 15.0
5 Florent 16.0 10.5
La méthode info() fournit un résumé plus détaillé : le nombre de lignes, les noms des colonnes,
leurs types de données et le nombre de valeurs non nulles. Appliquons-la au DataFrame météorolo-
gique :
>>> df_meteo = pd.read_excel('[Link]')
>>> print(df_meteo.info())
<class '[Link]'>
RangeIndex: 7 entries, 0 to 6
Data columns (total 3 columns):
# Column Non−Null Count Dtype
−−− −−−−−− −−−−−−−−−−−−−− −−−−−
0 Date 7 non−null object
1 Température 7 non−null float64
2 Précipitations 7 non−null float64
dtypes: float64(2), object(1)
memory usage: 300.0+ bytes
>>> print(df_meteo.info(memory_usage="deep"))
<class '[Link]'>
RangeIndex: 7 entries, 0 to 6
Data columns (total 3 columns):
# Column Non−Null Count Dtype
−−− −−−−−− −−−−−−−−−−−−−− −−−−−
0 Date 7 non−null object
1 Température 7 non−null float64
2 Précipitations 7 non−null float64
dtypes: float64(2), object(1)
memory usage: 657.0 bytes
Cette sortie indique que df_meteo contient 7 lignes (index de 0 à 6) et 3 colonnes : Date (type
object, c’est-à-dire une chaîne), Température et Précipitations (type float64). Toutes les
colonnes ont 7 valeurs non nulles, confirmant l’absence de données manquantes. Avec l’argument
memory_usage="deep", la méthode .info() permet de connaitre avec précision la quantité de
mémoire vive occupée par le Dataframe (environ 657 octets).
Note. La méthode info() affiche les types de données détectés automatiquement par Pandas. Si
une colonne, comme Date, est lue comme object (correspond la plupart du temps à des chaînes de
caractères) au lieu d’un type date (datetime), vous devrez peut-être convertir le type explicitement.
Pour le faire, vous utiliserez la méthode .to_datetime(). pandas détectera alors automatiquement
le format de date utilisé, si le format est homogène sur tout le jeu de données et non ambigu.
>>> df_meteo['Date'] = pd.to_datetime(df_meteo['Date'])
>>> print(df_meteo.info(memory_usage="deep"))
<class '[Link]'>
RangeIndex: 7 entries, 0 to 6
Data columns (total 3 columns):
# Column Non−Null Count Dtype
−−− −−−−−− −−−−−−−−−−−−−− −−−−−
0 Date 7 non−null datetime64[ns]
1 Température 7 non−null float64
2 Précipitations 7 non−null float64
dtypes: datetime64[ns](1), float64(2)
memory usage: 300.0 bytes
On remarque maintenant que le type de données de la colonne Date est maintenant une date
(datetime64[ns]).
Les statistiques descriptives permettent de résumer les propriétés numériques d’un DataFrame,
comme la moyenne, l’écart-type ou les valeurs extrêmes et offre un premier aperçu des tendances et
de la variabilité des données. Pandas fournit la méthode describe() pour calculer automatiquement
ces statistiques pour les colonnes numériques, ainsi que des fonctions spécifiques comme mean(),
std() ou min() pour des calculs ciblés. Ces outils peuvent se révéler utiles pour identifier des
motifs ou des anomalies avant une analyse plus approfondie.
Appliquons describe() au DataFrame des notes pour examiner les colonnes numériques :
>>> print(df_notes.describe())
Maths Physique
count 6.000000 6.000000
mean 14.166667 13.416667
std 3.044120 2.311205
min 9.500000 10.500000
25% 12.500000 11.625000
50% 14.750000 13.750000
75% 15.875000 14.750000
max 18.000000 16.500000
La colonne Nom (type object) est exclue, car describe() se concentre sur les colonnes numériques
par défaut. Pour inclure toutes les colonnes, vous pouvez utiliser df_notes.describe(include='
all'), mais cela ajoute des statistiques pour les chaînes (comme le nombre de valeurs uniques),
moins pertinentes ici.
Pour des calculs spécifiques, utilisez des fonctions comme mean() ou median(). Par exemple, pour
le DataFrame météorologique :
>>> print(df_meteo[['Température', 'Précipitations']].mean())
Température 6.071429
Précipitations 3.071429
dtype: float64
>>> print(df_meteo['Température'].median())
6.0
Ce code calcule :
• La moyenne des colonnes Température (6.07°C) et Précipitations (3.07 mm).
• La médiane de Température (6.0°C) qui est la valeur centrale lorsque les données sont
ordonnées.
Note. Ne vous inquiétez pas si la syntaxe df_meteo[['Température', 'Précipitations']] ou
df_meteo['Température'] ne vous est pas encore familière. Il s’agit de la sélection de colonnes
dans un tableau de données et nous verrons cela en détail dans la section suivante.
Le tableau suivant récapitule les principales fonctions statistiques :
Fonction Description
describe() Génère un résumé statistique (comptage, moyenne,
écart-type, quartiles, etc.) pour les colonnes numé-
riques.
mean() Calcule la moyenne des valeurs d’une colonne ou
d’un DataFrame.
median() Retourne la médiane (50e centile) des valeurs.
std() Calcule l’écart-type, mesurant la dispersion des don-
nées.
min(), max() Retourne les valeurs minimale et maximale.
count() Compte le nombre de valeurs non nulles.
Note. Les fonctions comme mean() ou std() s’appliquent aux colonnes numériques. Si une
colonne contient des chaînes ou des données non numériques, elles seront ignorées, sauf si vous
convertissez les données au préalable.
La sélection consiste à extraire des parties spécifiques d’un DataFrame, comme une colonne, une
ligne ou un sous-ensemble de données, pour se concentrer sur les informations pertinentes. Pandas
propose plusieurs méthodes pour effectuer ces sélections, notamment l’utilisation des crochets
([]) et les méthodes loc[] et iloc[] qui permettent d’accéder aux données par étiquettes ou par
positions numériques.
Pour illustrer, reprenez le fichier [Link] créé dans la section précédente, contenant les noms
et les notes en Maths et Physique de six étudiants. Commencez par sélectionner une ou plusieurs
colonnes :
>>> df_notes = pd.read_csv('[Link]')
>>> print(df_notes['Maths'])
0 15.5
1 12.0
2 18.0
3 9.5
4 14.0
5 16.0
Name: Maths, dtype: float64
>>> print(df_notes[['Nom', 'Physique']])
Nom Physique
0 Alice 14.0
1 Bob 13.5
2 Claire 16.5
3 David 11.0
4 Emma 15.0
5 Florent 10.5
La commande df_notes['Maths'] retourne une Series avec les notes en Maths, tandis que
df_notes[['Nom', 'Physique']] produit un DataFrame contenant uniquement les colonnes
colonnes Nom et Physique. Cette distinction est importante : une seule colonne donne une Series,
tandis que plusieurs colonnes donnent un DataFrame.
Pour sélectionner des lignes, utilisez loc[] (basé sur les étiquettes) ou iloc[] (basé sur les
positions numériques). Supposons que vous définissez Nom comme index pour faciliter l’accès par
nom :
>>> df_notes = df_notes.set_index('Nom')
>>> print(df_notes.loc['Alice'])
Maths 15.5
Physique 14.0
Name: Alice, dtype: float64
>>> print(df_notes.iloc[1])
Maths 12.0
Physique 13.5
Name: Bob, dtype: float64
Ici, df_notes.loc['Alice'] retourne une Series avec les notes d’Alice et df_notes.iloc[1]
retourne les notes de Bob (deuxième ligne). Vous pouvez également sélectionner des sous-ensembles
précis :
>>> print(df_notes.loc[['Alice', 'Claire'], 'Maths'])
Nom
Alice 15.5
Claire 18.0
Name: Maths, dtype: float64
>>> print(df_notes.iloc[0:2, 1])
Nom
Alice 14.0
Bob 13.5
Name: Physique, dtype: float64
Ces commandes extraient des sous-ensembles spécifiques, comme les notes en Maths pour Alice et
Claire ou les notes en Physique pour les deux premiers étudiants.
Note. Vérifiez les étiquettes d’index et de colonnes avant d’utiliser loc[], car une étiquette
inexistante provoque une erreur. Avec iloc[], assurez-vous que les indices numériques sont dans
les limites du DataFrame (de 0 à n−1 pour n lignes).
Le tableau suivant récapitule les méthodes de sélection :
Méthode Description
df['colonne'] Sélectionne une colonne sous forme de Series.
df[['col1', 'col2']] Sélectionne plusieurs colonnes sous forme de
DataFrame.
loc[étiquette] Sélectionne des lignes ou cellules par étiquettes d’in-
dex ou de colonnes.
iloc[position] Sélectionne des lignes ou cellules par positions nu-
mériques.
Le filtrage consiste à extraire les lignes d’un DataFrame qui satisfont des critères spécifiques,
comme des notes supérieures à une certaine valeur ou des jours avec des précipitations. À l’instar de
NumPy, Pandas utilise des masques booléens, créés avec des conditions, pour effectuer ce filtrage.
Reprenez le DataFrame df_notes (avec Nom comme index). Pour sélectionner les étudiants ayant
une note en Maths supérieure à 15 :
>>> print(df_notes[df_notes['Maths'] > 15])
Maths Physique
Nom
Alice 15.5 14.0
Claire 18.0 16.5
Florent 16.0 10.5
Le masque df_notes['Maths'] > 15 crée une Series de valeurs booléennes (True si la note
est supérieure à 15, False sinon). Appliquer df_notes[df_notes['Maths'] > 15] retourne un
DataFrame avec les lignes d’Alice, de Claire et de Florent dont les notes en Maths sont supérieures
à 15.
Pour des conditions multiples, combinez les masques avec des opérateurs logiques (& pour « ET », |
pour « OU », ~ pour « NON »). Par exemple, pour trouver les étudiants avec une note en Maths
supérieure à 15 et en Physique supérieure à 14 :
>>> masque = (df_notes['Maths'] > 15) & (df_notes['Physique'] > 14)
>>> print(df_notes[masque])
Maths Physique
Nom
Claire 18.0 16.5
Les parenthèses garantissent l’ordre correct des opérations et & combine les conditions. Le résultat
montre que seule Claire satisfait les deux critères.
La méthode isin() permet de filtrer basé sur une liste de valeurs. Par exemple, pour sélectionner
Alice et Bob :
>>> print(df_notes[df_notes.[Link](['Alice', 'Bob'])])
Maths Physique
Nom
Alice 15.5 14.0
Bob 12.0 13.5
Ici, df_notes.[Link](['Alice', 'Bob']) crée un masque pour les lignes dont l’index est
Alice ou Bob.
Une alternative est la méthode query(), qui utilise une syntaxe de chaîne pour exprimer des
conditions. Par exemple, avec le DataFrame [Link] :
>>> df_meteo = pd.read_excel('[Link]')
>>> print(df_meteo.query('Température > 6'))
Date Température Précipitations
1 2023−01−02 6.5 2.5
3 2023−01−04 7.0 0.0
4 2023−01−05 8.5 1.0
La requête 'Température > 6' retourne les lignes où la température dépasse 6°C, montrant trois
jours correspondants. query() est concise mais moins flexible pour des conditions complexes.
Note. Lors de l’utilisation de conditions multiples, placez chaque condition entre parenthèses
pour éviter des erreurs de priorité d’opérateurs. Par exemple, df['A'] > 5 & df['B'] < 10 peut
produire des résultats incorrects sans parenthèses.
Note. La méthode query() est utile pour des filtres simples, mais les masques booléens sont plus
courants dans la pratique, car ils sont plus flexibles et compatibles avec des opérations avancées.
Le tableau suivant récapitule les outils de filtrage :
Outil Description
df[condition] Filtre les lignes avec un masque booléen (par
exemple, df['col'] > valeur).
isin(liste) Filtre les lignes où une colonne ou l’index est dans
une liste de valeurs.
query('condition') Filtre avec une condition exprimée sous forme de
chaîne.
Modifier et ajouter des données dans un DataFrame permet de corriger des erreurs, d’enrichir les
données avec de nouvelles informations ou de supprimer des éléments inutiles. Ces opérations
sont essentielles pour préparer un dataset à une analyse. Pandas offre des méthodes simples pour
modifier des valeurs, ajouter des colonnes ou des lignes et supprimer des éléments.
Reprenez df_notes. Pour corriger une note erronée, par exemple en changeant la note en Maths de
David à 10.0 :
>>> df_notes.loc['David', 'Maths'] = 10.0
>>> print(df_notes)
Maths Physique
Nom
Alice 15.5 14.0
Bob 12.0 13.5
Claire 18.0 16.5
David 10.0 11.0
Emma 14.0 15.0
Florent 16.0 10.5
Maths Physique
Nom
Alice 15.5 14.0
Bob 12.0 13.5
Claire 18.0 16.5
David 10.0 12.0
Emma 14.0 15.0
Ici, le masque df_notes['Physique'] < 12 identifie les lignes de David et de Florent, et ajoute 1
à leurs notes.
Pour ajouter une nouvelle colonne, par exemple une moyenne des notes en Maths et Physique :
>>> df_notes['Moyenne'] = (df_notes['Maths'] + df_notes['Physique']) / 2
>>> print(df_notes)
Maths Physique Moyenne
Nom
Alice 15.5 14.0 14.75
Bob 12.0 13.5 12.75
Claire 18.0 16.5 17.25
David 10.0 12.0 11.00
Emma 14.0 15.0 14.50
Florent 16.0 11.5 13.75
La nouvelle colonne Moyenne est calculée comme la moyenne des deux notes pour chaque étudiant.
Pour ajouter une nouvelle ligne, par exemple un nouvel étudiant, utilisez [Link]. Créez un
DataFrame pour le nouvel étudiant et concaténez-le :
La fonction [Link] ajoute la ligne de Georges en alignant les colonnes existantes. La Moyenne
est précalculée pour correspondre à la structure du DataFrame.
Enfin, pour supprimer une colonne ou une ligne, utilisez drop. Par exemple, pour supprimer la
colonne Physique :
>>> df_notes = df_notes.drop('Physique', axis=1)
>>> print(df_notes)
Maths Moyenne
Alice 15.5 14.75
Bob 12.0 12.75
Claire 18.0 17.25
David 10.0 11.00
Emma 14.0 14.50
Florent 16.0 13.75
Georges 16.0 15.75
L’argument axis=1 indique une suppression de colonne. Pour supprimer une ligne, par exemple
David :
1 df_notes = df_notes.drop('David', axis=0)
2 print(df_notes)
L’argument axis=0 spécifie une suppression de ligne. Notez que drop ne modifie pas le DataFrame
original à moins d’assigner le résultat ou d’utiliser inplace=True.
Note. Lors de l’ajout de lignes ou de colonnes, assurez-vous que les types et les noms des colonnes
correspondent à ceux du DataFrame existant pour éviter des erreurs d’alignement. Avec drop,
vérifiez l’argument axis pour distinguer les lignes (axis=0) des colonnes (axis=1).
Le tableau suivant récapitule les méthodes de modification :
Méthode Description
loc[], iloc[] Modifie des cellules ou sous-ensembles spécifiques.
df['col'] = ... Ajoute ou modifie une colonne avec des valeurs ou
calculs.
[Link] Ajoute des lignes en combinant des DataFrames.
drop(label, axis) Supprime des lignes (axis=0, par défaut) ou des co-
lonnes (axis=1). Lorsqu’on ajoute inplace=True,
le DataFrame est modifié sur place.
Le regroupement consiste à organiser les données en catégories basées sur une ou plusieurs colonnes
puis à appliquer des fonctions d’agrégation, comme la moyenne ou la somme, pour résumer chaque
groupe. Cette opération est réalisée avec la méthode groupby. Elle est utile pour analyser des
données structurées.
Reprenez le fichier [Link] créé précédemment, contenant les noms et les notes en Maths et
Ce code crée un DataFrame où chaque ligne représente une note pour une matière spécifique. La
méthode groupby('Matière') regroupe les lignes par valeur de la colonne Matière (Maths ou
Physique) et mean() calcule la moyenne des notes pour chaque groupe. Le résultat montre que la
moyenne en Maths est de 13.8 et en Physique de 14.0.
Vous pouvez appliquer plusieurs fonctions d’agrégation avec agg. Par exemple, pour obtenir la
moyenne et le nombre de notes par matière :
1 print(groupe['Note'].agg(['mean', 'count']))
mean count
Matière
Maths 13.8 5
Physique 14.0 5
Ce code ajoute une colonne Statut indiquant si le jour est sec (Précipitations == 0) ou pluvieux
puis calcule la température moyenne pour chaque groupe. Les jours pluvieux ont une température
moyenne de 6.1°C, contre 6°C pour les jours secs.
Note. Lors de l’utilisation de groupby, assurez-vous que la colonne de regroupement contient des
catégories bien définies. Une colonne avec trop de valeurs uniques (par exemple, des températures
continues) peut produire un grand nombre de groupes inutiles.
Le tableau suivant récapitule les fonctions d’agrégation courantes :
Fonction Description
mean() Calcule la moyenne des valeurs dans chaque groupe.
sum() Calcule la somme des valeurs dans chaque groupe.
count() Compte le nombre de valeurs non nulles par groupe.
min(), max() Retourne les valeurs minimale et maximale par
groupe.
agg([f1, f2]) Applique plusieurs fonctions d’agrégation simultané-
ment.
Au-delà des statistiques descriptives de base, Pandas permet de calculer des mesures avancées,
comme l’écart-type, la variance, les quantiles et les corrélations entre variables. Ces outils, bien
que reposant sur des concepts statistiques, sont accessibles grâce à des fonctions simples et aident
à comprendre la variabilité et les relations dans vos données. Par exemple, vous pourriez vouloir
savoir si les notes en Maths et en Physique sont corrélées ou identifier les températures extrêmes
dans un relevé météorologique.
Reprenez le DataFrame [Link] initial. Pour calculer l’écart-type et la variance des notes :
>>> df_notes = pd.read_csv('[Link]')
>>> print(df_notes[['Maths', 'Physique']].std())
Maths 3.044120
Physique 2.311205
dtype: float64
>>> print(df_notes[['Maths', 'Physique']].var())
Maths 9.266667
Physique 5.341667
dtype: float64
L’écart-type (std()) mesure la dispersion des notes autour de la moyenne : un écart-type plus élevé
en Maths (3.04) indique une plus grande variabilité qu’en Physique (2.31). La variance (var()),
qui est le carré de l’écart-type, confirme cette observation (9.2 pour Maths, 5.3 pour Physique).
Pour calculer les quantiles, qui divisent les données en pourcentages, utilisez quantile. Par
Le résultat (17.0) indique que 90% des notes en Maths sont inférieures ou égales à 17.1, une mesure
utile pour identifier les performances exceptionnelles.
La corrélation mesure la relation linéaire entre deux variables numériques. Pandas utilise corr()
pour calculer le coefficient de corrélation de Pearson, qui varie de -1 (corrélation négative parfaite)
à 1 (corrélation positive parfaite), avec 0 indiquant aucune corrélation. Pour examiner la corrélation
entre les notes en Maths et en Physique :
>>> print(df_notes[['Maths', 'Physique']].corr())
Maths Physique
Maths 1.000000 0.514054
Physique 0.514054 1.000000
La corrélation de 0.51 entre Maths et Physique suggère une corrélation positive modérée : les
étudiants qui ont de bonnes notes en Maths ont souvent aussi de bonnes notes en Physique, et
inversement. La diagonale (1.0) reflète la corrélation d’une variable avec elle-même.
Pour un exemple avec [Link], calculez la corrélation entre Température et Précipitations :
>>> print(df_meteo[['Température', 'Précipitations']].corr())
Température Précipitations
Température 1.000000 −0.655985
Précipitations −0.655985 1.000000
La corrélation de -0.16 indique une relation négative modérée à forte : plus la température est
élevée, moins il y a de précipitations, et inversement. Plus simplement, il fait souvent plus sec
quand il fait chaud.
Notes.
• La corrélation de Pearson suppose une relation linéaire. Si les variables ont une relation non
linéaire ou contiennent des valeurs aberrantes, le coefficient peut ne pas refléter fidèlement
leur lien. Vérifiez toujours vos données avec des visualisations, comme des diagrammes de
dispersion, avant d’interpréter les corrélations.
• Pour des analyses avancées, vous pouvez utiliser corr(method='spearman') ou corr(
method='kendall') pour des corrélations non linéaires, mais ces méthodes sont générale-
ment abordées dans des cours plus avancés.
Le tableau suivant résume les types de corrélations disponibles dans corr() :
Méthode Description
'pearson' Mesure la corrélation linéaire (par défaut).
'spearman' Mesure la corrélation basée sur les rangs, adaptée
aux relations non linéaires.
'kendall' Mesure la corrélation ordinale, robuste pour les petits
échantillons.
Pandas propose une large gamme de fonctions pour analyser les données, allant des statistiques
descriptives aux mesures de relation. Ces fonctions, appliquées à des Series ou des DataFrames,
sont essentielles pour résumer, comparer et interpréter les données. Le tableau suivant liste les
fonctions couramment utilisées, avec leurs descriptions et cas d’usage, pour vous offrir une référence
complète et pratique.
Fonction Description
mean() Calcule la moyenne des valeurs, utile pour résumer une variable
(par exemple, moyenne des notes).
median() Retourne la médiane (50e centile), robuste aux valeurs aberrantes
(par exemple, médiane des températures).
std() Calcule l’écart-type, mesurant la dispersion autour de la moyenne
(par exemple, variabilité des notes).
var() Calcule la variance, indiquant la dispersion au carré (par exemple,
variance des précipitations).
min() Retourne la valeur minimale, pour identifier les extrêmes (par
exemple, température la plus basse).
max() Retourne la valeur maximale, pour identifier les pics (par exemple,
note la plus élevée).
sum() Calcule la somme des valeurs, utile pour les totaux (par exemple,
total des précipitations).
count() Compte le nombre de valeurs non nulles, pour vérifier la complé-
tude (par exemple, nombre de notes).
quantile(q) Calcule le quantile spécifié (par exemple, q=0.25 pour le 25e
centile), pour étudier la répartition.
describe() Génère un résumé statistique (comptage, moyenne, écart-type,
quartiles, etc.) pour les colonnes numériques.
corr() Calcule la matrice de corrélations entre colonnes numériques, pour
étudier les relations (par exemple, corrélation Maths-Physique).
cov() Calcule la covariance entre colonnes, mesurant la variation
conjointe (par exemple, covariance des notes).
mode() Retourne la valeur la plus fréquente, utile pour les données catégo-
riques (par exemple, statut météo le plus courant).
nunique() Compte le nombre de valeurs uniques, pour évaluer la diversité
(par exemple, nombre de matières distinctes).
value_counts() Compte la fréquence de chaque valeur dans une Series, pour ana-
lyser les distributions (par exemple, fréquence des statuts météo).
Note. Certaines fonctions, comme sum() ou count(), peuvent être utilisées avec groupby pour des
analyses par groupe, tandis que corr() et cov() s’appliquent uniquement aux colonnes numériques.
Testez toujours vos données pour vous assurer qu’elles sont adaptées à la fonction choisie.
La gestion des données manquantes est une étape importante pour garantir la fiabilité des analyses,
car elles peuvent fausser les statistiques ou empêcher certaines opérations. Pandas offre des outils
simples et puissants pour détecter, traiter et évaluer l’impact des valeurs manquantes, permettant de
préparer les données pour des analyses performantes.
La première étape pour gérer les données manquantes consiste à les identifier dans un DataFrame.
Pandas fournit des méthodes comme isna(), notna() et info() pour localiser et quantifier ces
valeurs, vous permettant de comprendre l’étendue du problème avant de décider comment le traiter.
Pour illustrer, modifiez le fichier [Link] utilisé précédemment pour inclure des valeurs man-
quantes en simulant un scénario où certaines notes n’ont pas été enregistrées :
1 import pandas as pd
2 import numpy as np
3
4 # Création d'un DataFrame avec des valeurs manquantes
5 notes = {
6 'Nom': ['Alice', 'Bob', 'Claire', 'David', 'Emma'],
7 'Maths': [15.5, 12.0, [Link], 9.5, 14.0],
8 'Physique': [14.0, [Link], 16.5, 11.0, [Link]]
9 }
10 df_notes = [Link](notes)
11 df_notes.to_csv('notes_manquantes.csv', index=False)
12
13 # Détection avec info()
14 print(df_notes.info())
<class '[Link]'>
RangeIndex: 5 entries, 0 to 4
Data columns (total 3 columns):
# Column Non−Null Count Dtype
−−− −−−−−− −−−−−−−−−−−−−− −−−−−
0 Nom 5 non−null object
1 Maths 4 non−null float64
2 Physique 3 non−null float64
dtypes: float64(2), object(1)
memory usage: 252.0+ bytes
La méthode info() montre que la colonne Maths a 4 valeurs non nulles (une manquante) et
Physique a 3 valeurs non nulles (deux manquantes), tandis que Nom est complète. Cela indique que
des données sont absentes pour certains étudiants.
Pour localiser précisément les valeurs manquantes, utilisez isna(), qui retourne un DataFrame de
valeurs booléennes (True pour les NaN, False sinon) :
>>> df_notes = pd.read_csv('notes_manquantes.csv')
>>> print(df_notes.isna())
Nom Maths Physique
0 False False False
1 False False True
2 False True False
3 False False False
4 False False True
Ce résultat montre que Claire manque une note en Maths, Bob et Emma manquent une note en
Physique. Pour compter le nombre de valeurs manquantes par colonne, combinez isna() avec
sum() :
>>> print(df_notes.isna().sum())
Nom 0
Maths 1
Physique 2
dtype: int64
La méthode notna() fonctionne de manière inverse, retournant True pour les valeurs présentes.
Par exemple, pour vérifier les lignes avec des notes complètes :
>>> print(df_notes[df_notes.notna().all(axis=1)])
Nom Maths Physique
0 Alice 15.5 14.0
3 David 9.5 11.0
On a utilisé notna().all(axis=1) pour identifier les lignes où toutes les colonnes sont non nulles,
cela montre que seuls Alice et David ont des notes complètes.
Note. Lors de l’importation de fichiers, Pandas peut interpréter certaines valeurs (par exemple, «
NA », « - ») comme manquantes si spécifié dans pd.read_csv ou pd.read_excel avec l’argument
na_values. Vérifiez toujours les données importées avec info() pour détecter ces cas.
Une fois les valeurs manquantes identifiées, vous devez décider de les supprimer ou de les remplacer
(imputer) par des valeurs appropriées. La suppression, réalisée avec dropna, élimine les lignes
ou colonnes contenant des NaN, tandis que l’imputation, via fillna ou des méthodes comme
l’interpolation, remplace les NaN par des estimations. Chaque approche a ses avantages et ses limites
et le choix dépend du contexte et de l’impact sur l’analyse.
Reprenez df_notes avec les valeurs manquantes. Pour supprimer les lignes contenant au moins
une valeur manquante :
>>> df_notes = pd.read_csv('notes_manquantes.csv')
>>> df_clean = df_notes.dropna()
>>> print(df_clean)
Nom Maths Physique
0 Alice 15.5 14.0
3 David 9.5 11.0
La méthode dropna() supprime les lignes de Bob, Claire, et Emma, car elles contiennent des NaN,
ne laissant que les lignes complètes. Pour supprimer uniquement les lignes où toutes les valeurs
numériques sont manquantes, utilisez how='all' (inutile ici, car aucune ligne n’est entièrement
NaN).
L’argument axis=1 supprime Maths et Physique, car elles contiennent des NaN, ne laissant que
Nom. Cette approche est rarement utilisée, car elle peut éliminer des variables essentielles.
L’imputation remplace les NaN par des valeurs estimées. Une méthode courante est de remplir avec
la moyenne de la colonne :
>>> df_impute = df_notes.copy()
>>> df_impute['Maths'] = df_impute['Maths'].fillna(df_impute['Maths'].mean())
>>> df_impute['Physique'] = df_impute['Physique'].fillna(df_impute['Physique
'].mean())
>>> print(df_impute)
Nom Maths Physique
0 Alice 15.50 14.000000
1 Bob 12.00 13.833333
2 Claire 12.75 16.500000
3 David 9.50 11.000000
4 Emma 14.00 13.833333
Ce code remplace la note manquante en Maths (Claire) par la moyenne des notes en Maths (12.75)
et les notes manquantes en Physique (Bob, Emma) par la moyenne en Physique (13.833). La
méthode copy() évite de modifier df_notes original.
Pour un exemple avec [Link], imputez les précipitations manquantes (en supposant une valeur
manquante ajoutée) par interpolation linéaire, adaptée aux données temporelles :
1 import pandas as pd
2 import numpy as np
3
4 meteo = {
5 'Date': ['2023−01−01', '2023−01−02', '2023−01−03', '2023−01−04',
6 '2023−01−05', '2023−01−06', '2023−01−07'],
7 'Température': [5.0, 6.5, 4.0, 7.0, 8.5, 5.5, 6.0],
8 'Précipitations': [0.0, 2.5, [Link], 0.0, 1.0, 5.0, 3.0]
9 }
10 df_meteo = [Link](meteo)
11 df_meteo.to_excel('meteo_manquantes.xlsx', index=False)
12
13 df_meteo['Précipitations'] = df_meteo['Précipitations'].interpolate(method='
linear')
14 print(df_meteo)
L’interpolation linéaire estime la valeur manquante du 3 janvier (1.25 mm) comme la moyenne des
valeurs adjacentes (2.5 et 0.0), ce qui est adapté aux données continues comme les précipitations.
Note. L’imputation par la moyenne peut introduire un biais, surtout si les valeurs manquantes ne
sont pas aléatoires. L’interpolation est plus adaptée aux données séquentielles, comme les séries
temporelles, mais peut être inexacte si les variations sont irrégulières.
Le tableau suivant récapitule les méthodes de traitement :
Méthode Description
dropna() Supprime les lignes (axis=0, par défaut) ou colonnes
(axis=1) contenant des NaN.
dropna(how='all') Supprime les lignes ou colonnes où toutes les valeurs
sont NaN.
fillna(valeur) Remplace les NaN par une valeur fixe (par exemple,
0, moyenne).
interpolate(method='linear') Estime les NaN par interpolation linéaire, adapté aux
données continues.
Le traitement des valeurs manquantes prépare vos données pour l’analyse, mais il est important
d’évaluer son impact.
Le choix de supprimer ou d’imputer les valeurs manquantes peut influencer les résultats de vos
analyses, comme les moyennes, les corrélations ou les regroupements. Une suppression excessive
peut réduire la taille de l’échantillon, entraînant une perte d’information, tandis qu’une imputation
inappropriée peut introduire des biais.
Reprenez df_notes avec les valeurs manquantes et comparez la moyenne des notes avant et après
traitement. Calculez d’abord la moyenne sans traitement :
>>> df_notes = pd.read_csv('notes_manquantes.csv')
>>> print(df_notes[['Maths', 'Physique']].mean())
Maths 12.750000
Physique 13.833333
dtype: float64
Les moyennes sont calculées en ignorant les NaN (4 notes pour Maths, 3 pour Physique). Après
suppression des lignes avec NaN :
>>> print(df_notes.dropna()[['Maths', 'Physique']].mean())
Maths 12.5
Physique 12.5
dtype: float64
La suppression réduit l’échantillon à deux lignes (Alice, David), modifiant légèrement les moyennes
(12.5 au lieu de 12.75 et 13.83). Cela montre une perte d’information, car les données de Claire,
Bob et Emma sont exclues.
Comparez avec l’imputation par la moyenne (utilisant df_impute créé précédemment) :
>>> print(df_impute[['Maths', 'Physique']].mean())
Maths 12.750000
Physique 13.833333
dtype: float64
L’imputation préserve toutes les lignes, maintenant les moyennes initiales (12.75, 13.83), mais elle
suppose que les valeurs manquantes sont similaires à la moyenne, ce qui peut ne pas refléter la
réalité (par exemple, la note manquante de Claire pourrait être plus élevée).
Note. Avant de finaliser le traitement, comparez toujours les statistiques (moyennes, écarts-types)
ou les visualisations avant et après pour évaluer l’impact. Si possible, documentez la méthode
choisie et ses hypothèses pour garantir la transparence de votre analyse.
La concaténation consiste à combiner plusieurs DataFrames en les alignant soit verticalement (ajout
de lignes, comme empiler des pages) soit horizontalement (ajout de colonnes, comme juxtaposer
des tableaux). La fonction [Link] est utilisée pour cette tâche.
Pour illustrer la concaténation verticale, créez deux DataFrames représentant des notes d’étudiants
de deux classes différentes, puis combinez-les :
1 import pandas as pd
2
3 # Création de deux DataFrames
4 classe1 = {
5 'Nom': ['Alice', 'Bob', 'Claire'],
6 'Maths': [15.5, 12.0, 18.0],
7 'Physique': [14.0, 13.5, 16.5]
8 }
9 classe2 = {
10 'Nom': ['David', 'Emma'],
11 'Maths': [9.5, 14.0],
12 'Physique': [11.0, 15.0]
13 }
14 df_classe1 = [Link](classe1)
15 df_classe2 = [Link](classe2)
16
17 # Concaténation verticale
18 df_notes = [Link]([df_classe1, df_classe2], ignore_index=True)
19 print(df_notes)
1 chimie = [Link]({
2 'Chimie': [13.0, 11.5, 17.0, 10.0, 14.5]
3 })
4 df_notes_avec_chimie = [Link]([df_notes, chimie], axis=1)
5 print(df_notes_avec_chimie)
L’argument axis=1 indique une concaténation horizontale, ajoutant la colonne Chimie à droite du
DataFrame. Les lignes sont alignées par index, ce qui nécessite que les DataFrames aient le même
nombre de lignes.
Note. Lors de la concaténation, assurez-vous que les DataFrames ont des structures compatibles.
Pour une concaténation verticale, les colonnes doivent avoir les mêmes noms ; pour une concaténa-
tion horizontale, le nombre de lignes doit correspondre. Des incohérences peuvent introduire des
NaN ou des erreurs.
Paramètre Description
objs Liste des DataFrames à concaténer.
axis 0 pour une concaténation verticale (lignes), 1 pour
horizontale (colonnes).
ignore_index Si True, réinitialise l’index du DataFrame résultant.
join Type d’alignement ('inner' pour l’intersection, '
outer' pour l’union des colonnes).
La jointure relie deux DataFrames en fonction d’une ou plusieurs colonnes clés. Pandas propose
merge pour des jointures basées sur des colonnes et join pour des jointures basées sur des index,
avec différents types de jointures : inner (intersection), left (priorité au premier DataFrame),
right (priorité au second) et outer (union).
Pour illustrer, créez un DataFrame avec des informations sur les étudiants (par exemple, leur classe)
et joignez-le à df_notes :
1 # Création d'un DataFrame d'informations
2 infos = {
3 'Nom': ['Alice', 'Bob', 'Claire', 'Fiona'],
4 'Classe': ['A', 'B', 'A', 'B']
5 }
6 df_infos = [Link](infos)
7
8 # Jointure avec merge
9 df_merge = [Link](df_notes, df_infos, on='Nom', how='inner')
10 print(df_merge)
La fonction [Link] joint df_notes et df_infos sur la colonne Nom, avec une jointure inner
(seules les lignes avec des Nom présents dans les deux DataFrames sont conservées). David et
Emma (absents de df_infos) et Fiona (absente de df_notes) sont exclus.
Pour inclure tous les étudiants de df_notes, utilisez une jointure left :
1 df_merge_left = [Link](df_notes, df_infos, on='Nom', how='left')
2 print(df_merge_left)
La jointure left conserve toutes les lignes de df_notes et ajoute NaN pour David et Emma qui
n’ont pas de correspondance dans df_infos.
La méthode join est utile lorsque les DataFrames partagent un index commun. Définissez Nom
comme index pour les deux DataFrames et effectuez une jointure :
1 df_notes_idx = df_notes.set_index('Nom')
2 df_infos_idx = df_infos.set_index('Nom')
3 df_join = df_notes_idx.join(df_infos_idx, how='inner')
4 print(df_join)
La méthode join aligne les DataFrames sur leurs index (Nom) et produit un résultat similaire à la
jointure inner de merge. join est plus concise lorsque les index sont déjà définis.
Note. Lors d’une jointure, vérifiez que la colonne ou l’index de jointure (par exemple, Nom) est
présent dans les deux DataFrames et a des valeurs compatibles. Des clés dupliquées ou des types
de données différents (par exemple, chaînes vs nombres) peuvent provoquer des erreurs ou des
résultats inattendus.
Le tableau suivant récapitule les types de jointures :
Type Description
inner Conserve uniquement les lignes avec des clés pré-
sentes dans les deux DataFrames.
left Conserve toutes les lignes du premier DataFrame,
avec NaN pour les clés absentes du second.
right Conserve toutes les lignes du second DataFrame,
avec NaN pour les clés absentes du premier.
outer Conserve toutes les lignes des deux DataFrames,
avec NaN là où les clés ne correspondent pas.
Une fusion ou une concaténation peut créer des doublons, c’est-à-dire des lignes identiques ou
partiellement redondantes qui risquent de fausser les analyses (par exemple, en comptant deux fois
un étudiant). Pandas fournit duplicated pour détecter les doublons et drop_duplicates pour les
supprimer.
Pour illustrer, modifiez df_infos pour inclure un doublon (deux entrées pour Alice) et effectuez
une jointure :
1 # Création d'un DataFrame avec un doublon
2 infos_doublon = {
3 'Nom': ['Alice', 'Alice', 'Bob', 'Claire'],
4 'Classe': ['A', 'A', 'B', 'A']
5 }
6 df_infos_doublon = [Link](infos_doublon)
7
8 # Jointure avec doublon
9 df_merge_doublon = [Link](df_notes, df_infos_doublon, on='Nom', how='inner
')
10 print(df_merge_doublon)
La jointure crée deux lignes pour Alice, car Nom='Alice' apparaît deux fois dans df_infos_doublon
. Détectez les doublons avec duplicated :
1 print(df_merge_doublon.duplicated())
0 False
1 True
2 False
3 False
dtype: bool
La méthode duplicated() marque la deuxième ligne d’Alice comme un doublon (True). Pour
compter les doublons :
1 print(df_merge_doublon.duplicated().sum())
Exporter un DataFrame vers un fichier consiste à le convertir en un format lisible par d’autres
logiciels, comme un tableur ou un système de gestion de données. Pandas propose des méthodes
comme to_csv pour les fichiers CSV (Comma-Separated Values) et to_excel pour les fichiers
Excel, qui sont largement utilisés pour leur simplicité et leur compatibilité. Nous avons déjà utilisé
ces deux méthodes plus haut.
Reprenez le DataFrame [Link] initial, contenant les noms et les notes en Maths et Physique
de six étudiants. Après avoir ajouté une colonne Moyenne, exportez le DataFrame modifié vers un
nouveau fichier CSV (pour un fichier Excel, utilisez to_excel) :
1 import pandas as pd
2
3 # Chargement et ajout de la colonne Moyenne
4 df_notes = pd.read_csv('[Link]')
5 df_notes['Moyenne'] = (df_notes['Maths'] + df_notes['Physique']) / 2
6
7 # Exportation vers CSV
8 df_notes.to_csv('notes_avec_moyenne.csv')
à 5) est inclus comme première colonne dans le fichier. Pour vérifier le contenu du fichier, vous
pouvez le recharger :
1 print(pd.read_csv('notes_avec_moyenne.csv'))
Le fichier contient une colonne Unnamed: 0 correspondant à l’index, ce qui peut être indésirable et
compliquer la lecture du fichier. Pour exclure l’index :
1 df_notes.to_csv('notes_sans_index.csv', index=False)
2 print(pd.read_csv('notes_sans_index.csv'))
Les visualisations, comme les graphiques ou les diagrammes, complètent les données exportées
en offrant une représentation visuelle des résultats, facilitant leur interprétation. Matplotlib, une
bibliothèque de visualisation en Python, s’intègre parfaitement avec Pandas pour générer des
graphiques que vous pouvez sauvegarder et inclure dans des rapports ou des présentations.
Pour illustrer, créez un nuage de points montrant la relation entre les notes en Maths et en Physique
à partir de df_notes :
1 import pandas as pd
2 import [Link] as plt
3
4 df_notes = pd.read_csv('[Link]')
5
6 [Link](df_notes['Maths'], df_notes['Physique'], color='blue', alpha
=0.6)
7 [Link]('Notes en Maths')
8 [Link]('Notes en Physique')
9 [Link]('Relation entre les notes en Maths et en Physique')
10 [Link](True)
11 [Link]('nuage_notes.png', dpi=150, bbox_inches='tight')
12 [Link]()
Ce code génère un nuage de points où chaque point représente un étudiant, avec les notes en Maths
sur l’axe des abscisses et celles en Physique sur l’axe des ordonnées.
16
15
Notes en Physique
14
13
12
11
10 12 14 16 18
Notes en Maths
La programmation, telle que vous l’avez découverte dans les chapitres précédents, repose sur des
outils comme les variables, les fonctions et les modules pour structurer et résoudre des problèmes.
Ces outils sont puissants pour manipuler des données et automatiser des tâches, mais ils peuvent
devenir limités lorsque vous devez modéliser des entités complexes. La programmation orientée
objet (POO) introduit une nouvelle approche, où le code est organisé autour d’objets qui combinent
des données (comme les coordonnées d’un point) et des comportements (comme calculer une
distance). Ce paradigme, largement utilisé en informatique, permet de représenter des concepts du
monde réel de manière simple, facilitant la conception de programmes clairs, réutilisables et adaptés
aux problèmes scientifiques que vous rencontrerez dans vos études. Par exemple, représenter une
particule avec ses propriétés (masse, vitesse) et ses comportements (calcul d’énergie) devient
naturel avec la POO, car vous pouvez regrouper ces éléments dans un seul concept cohérent. De
plus, la POO favorise la réutilisabilité, car une classe bien conçue peut être utilisée dans plusieurs
projets et la modularité, car les classes peuvent être intégrées dans des modules.
Avant de plonger dans les détails techniques, il est utile de comprendre pourquoi la POO est un
outil puissant, en particulier pour des étudiants en CPGE. Voici quelques avantages clés :
• Représentation simple : La POO permet de modéliser des entités du monde réel, comme
une particule ou un vecteur, en regroupant leurs propriétés (par exemple, masse, coordonnées)
et leurs comportements (par exemple, calculer une force) dans une seule unité logique. Cela
rend le code plus proche de la manière dont vous pensez à un problème scientifique.
• Réutilisabilité : Une classe bien conçue, comme une classe Point pour la géométrie, peut
être réutilisée dans différents programmes (par exemple, pour des calculs vectoriels ou des
simulations).
• Maintenance : En regroupant les données et les opérations associées, la POO facilite la mo-
dification du code. Par exemple, ajouter une nouvelle fonctionnalité à une classe Particule
(comme calculer l’énergie cinétique) ne nécessite pas de réécrire tout le programme.
• Collaboration : Dans des projets plus complexes, la POO permet à plusieurs programmeurs
de travailler sur des classes distinctes, intégrées ensuite dans un module ou un package.
Cependant, la POO peut sembler abstraite au début, surtout si vous êtes habitués à écrire des
programmes linéaires avec des fonctions. Ne vous inquiétez pas : les concepts seront introduits
190 Chapitre 8. Introduction à la programmation orientée objet
étape par étape, avec des exemples concrets pour que vous puissiez rapidement appliquer la POO à
vos propres projets.
Exécution du script :
Dans cet exemple, Etudiant est une classe vide, définie avec pass pour indiquer qu’elle ne contient
encore ni attributs ni méthodes. Les objets etudiant1 et etudiant2 sont créés en « appelant » la
classe (Etudiant()). Des attributs nom et age sont ajoutés manuellement à chaque objet, ce qui
leur permet de stocker des informations spécifiques. La fonction isinstance() est utilisée pour
vérifier que etudiant1 et etudiant2 sont bien des instances de la classe Etudiant. Elle prend
deux arguments : l’objet à tester et la classe (ou le type) à vérifier, et retourne True si l’objet est
une instance de cette classe, False sinon.
Notes.
1. Ajouter des attributs manuellement, comme dans l’exemple ci-dessus, est possible mais
risqué et déconseillé, car il est facile d’oublier un attribut ou de faire des erreurs (par exemple,
écrire [Link] au lieu de age ou encore oublier d’ajouter un attribut). De plus, cela
rend le code moins structuré. La section 10.2 introduira le constructeur __init__, qui permet
d’initialiser les attributs de manière systématique et sécurisée.
2. La création d’un objet est appelée instanciation, car elle produit une instance de la classe.
Chaque objet est indépendant : modifier les attributs de etudiant1 (par exemple, etudiant1
.age = 20) n’affecte pas etudiant2. La fonction isinstance() permet de confirmer qu’un
objet est une instance d’une classe donnée, ce qui est utile pour vérifier le type d’un objet
avant de manipuler ses attributs ou méthodes. Cela reflète la puissance de la POO : une seule
classe peut générer de nombreux objets, chacun avec ses propres données.
Point 1 : (3, 4)
Point 2 : (−1, 2)
Point 1 après modification : (5, 4)
Dans cet exemple, self.x et self.y sont des attributs d’instance, car chaque objet (point1 et
point2) possède ses propres valeurs pour x et y. La méthode definir_coordonnees() utilise
self pour associer les valeurs x et y à l’objet appelant. Modifier point1.x n’affecte pas point2.x,
car chaque objet a sa propre copie des attributs.
Note. Les attributs d’instance sont créés dynamiquement lorsqu’ils sont assignés (par exemple,
dans definir_coordonnees()). Si vous essayez d’accéder à un attribut d’instance non défini
(par exemple, point1.z), Python lèvera une erreur AttributeError. La section 10.2 montrera
comment éviter ce problème avec le constructeur.
Point 1 : (3, 4)
Point 2 : (−1, 2)
Nombre total de points : 2
Nombre via point1 : 2
Dans cet exemple, nombre_points est un attribut de classe, défini une seule fois dans la classe Point
. Chaque appel à definir_coordonnees() incrémente Point.nombre_points et cette valeur est
partagée par tous les objets. Vous pouvez y accéder via Point.nombre_points (recommandé) ou
via un objet comme point1.nombre_points, car les objets héritent des attributs de leur classe.
Pour visualiser la différence, supposons une école avec plusieurs étudiants. Les attributs d’instance
sont comme le nom ou l’âge de chaque étudiant, uniques à chacun. Un attribut de classe est comme
le nom de l’école, commun à tous les étudiants et stocké en un seul exemplaire. Si l’école change
de nom, tous les étudiants verront ce changement, tout comme modifier Point.nombre_points
affecte tous les objets.
Note. Si vous modifiez un attribut de classe via un objet en utilisant une assignation (par exemple,
point1.nombre_points = 10), Python crée un nouvel attribut d’instance nombre_points pour
point1, masquant l’attribut de classe sans affecter Point.nombre_points ni les autres objets.
Pour modifier l’attribut de classe, utilisez toujours le nom de la classe (par exemple, Point.
nombre_points = 5).
Cet exemple montre que point1.nombre_points = 10 ne modifie pas l’attribut de classe, mais
crée un attribut d’instance spécifique à point1. Cela peut entraîner des erreurs logiques dans votre
programme.
Récapitulatif : les classes, objets et attributs forment le socle de la programmation orientée objet.
Une classe définit un modèle, un objet est une instance concrète de ce modèle et les attributs
stockent les données, soit pour chaque objet (attributs d’instance) soit pour toutes les instances
(attributs de classe). Ces concepts vous permettent de représenter des entités complexes de manière
structurée.
Cependant, la méthode manuelle pour définir les attributs, comme dans les exemples ci-dessus, est
limitée, car elle oblige à appeler une méthode comme definir_coordonnees() après la création
de l’objet. La section suivante introduira le constructeur __init__ qui permet d’initialiser les
attributs d’instance automatiquement lors de la création d’un objet, ce qui rend le code plus robuste
et pratique.
• self, le premier paramètre, qui représente l’objet en cours de création (comme vu dans la
section 10.1 pour les attributs d’instance).
• Des paramètres supplémentaires, définis par vous, pour spécifier les valeurs initiales des
attributs.
Lorsque vous créez un objet avec objet = MaClasse(valeur1, valeur2), Python appelle auto-
matiquement __init__ en passant objet comme self et valeur1, valeur2 comme parametre1,
parametre2.
Voici une classe Point utilisant un constructeur pour initialiser les coordonnées d’un point dans un
espace bidimensionnel :
1 class Point:
2 def __init__(self, x, y):
3 """Initialise un point avec les coordonnées x et y."""
4 self.x = x
5 self.y = y
6
7 if __name__ == "__main__":
8 point1 = Point(3, 4)
9 point2 = Point(−1, 2)
10
11 print(f"Point 1 : ({point1.x}, {point1.y})")
Point 1 : (3, 4)
Point 2 : (−1, 2)
Dans cet exemple, le constructeur __init__ prend trois paramètres : self (l’objet en cours de
création), x et y (les coordonnées). Lorsque point1 = Point(3, 4) est exécuté, __init__ assigne
3 à self.x et 4 à self.y pour point1. Le résultat est un objet immédiatement utilisable, sans avoir
besoin d’appeler une méthode supplémentaire comme definir_coordonnees().
Note. Le nom __init__ est fixé par Python et ne peut pas être changé. Les doubles tirets bas
indiquent qu’il s’agit d’une méthode spéciale, gérée automatiquement par le langage. Vous ne
devez jamais appeler __init__ directement (par exemple, point1.__init__(5, 6)), car cela
réinitialiserait l’objet, ce qui est rarement souhaitable.
En Python, le paramètre self est utilisé dans les méthodes d’une classe pour faire référence
à l’instance de l’objet sur laquelle la méthode est appelée. Il permet d’accéder aux attributs et
autres méthodes de cet objet spécifique. Par convention, self est toujours le premier paramètre
des méthodes d’instance, car Python passe automatiquement l’instance comme argument lors de
l’appel de la méthode. Cela garantit que la méthode agit sur les données propres à l’instance. Par
exemple, si vous appelez point1.definir_coordonnees(3, 4), self fait référence à point1 en
garantissant que les attributs self.x et self.y sont assignés à point1 et non à un autre objet.
Omettre self entraînerait une erreur ou un comportement incorrect, car la méthode ne pourrait pas
identifier l’objet concerné. Bien que le nom self soit une convention (on pourrait utiliser un autre
nom), il est fortement recommandé pour la lisibilité et le respect des normes Python.
Le constructeur est généralement utilisé pour initialiser les attributs d’instance, mais il peut aussi
interagir avec les attributs de classe pour mettre à jour des données partagées. Par exemple, vous
pouvez utiliser un attribut de classe pour compter le nombre d’objets créés, en l’incrémentant dans
__init__.
En exemple, voici une classe Particule qui combine un attribut de classe et des attributs d’instance
avec un constructeur :
1 class Particule:
2 nombre_particules = 0 # Attribut de classe
3
4 def __init__(self, masse, vitesse):
5 """Initialise une particule avec une masse et une vitesse."""
6 [Link] = masse
7 [Link] = vitesse
8 Particule.nombre_particules += 1 # Incrémentation de l'attribut de
classe
9
10 if __name__ == "__main__":
11 particule1 = Particule(2.0, 10.0)
12 particule2 = Particule(1.5, 5.0)
13
14 print(f"Particule 1 : masse = {[Link]} kg, vitesse = {
[Link]} m/s")
15 print(f"Particule 2 : masse = {[Link]} kg, vitesse = {
[Link]} m/s")
16 print(f"Nombre total de particules : {Particule.nombre_particules}")
Dans cet exemple, nombre_particules est un attribut de classe, partagé par toutes les instances de
Particule. Le constructeur __init__ incrémente cet attribut à chaque création d’objet, permettant
de suivre le nombre total de particules. Les attributs masse et vitesse sont des attributs d’instance,
spécifiques à chaque particule.
De plus, comme pour les fonctions, le constructeur peut inclure des paramètres optionnels avec des
valeurs par défaut.
1 class Rectangle:
2 def __init__(self, longueur, largeur=1.0):
3 """Initialise un rectangle avec une longueur et une largeur (par dé
faut 1.0)."""
4 [Link] = longueur
5 [Link] = largeur
6
7 if __name__ == "__main__":
8 rectangle1 = Rectangle(5.0) # Largeur par défaut (1.0)
9 rectangle2 = Rectangle(3.0, 2.0) # Largeur spécifiée
10
11 print(f"Rectangle 1 : longueur = {[Link]}, largeur = {
[Link]}")
12 print(f"Rectangle 2 : longueur = {[Link]}, largeur = {
[Link]}")
Dans cet exemple, le paramètre largeur a une valeur par défaut de 1.0. Si vous créez un rectangle
sans spécifier la largeur (Rectangle(5.0)), elle prend la valeur par défaut. Cela rend la classe plus
flexible et pratique.
Note. Les valeurs par défaut dans __init__ suivent les mêmes règles que dans les fonctions.
Évitez d’utiliser des objets mutables (comme des listes) comme valeurs par défaut, car ils sont
partagés entre toutes les instances, ce qui peut entraîner des comportements inattendus. Par exemple,
def __init__(self, liste=[]) crée une seule liste partagée, modifiée par tous les objets.
12 [Link](15)
13 print(f"Notes d'Alice : {[Link]}")
14 print(f"Notes de Bob : {[Link]}") # Erreur : les notes sont
partagées !
Pour éviter ce problème, utilisez None comme valeur par défaut et initialisez une nouvelle liste dans
__init__ :
1 class Etudiant:
2 def __init__(self, nom, notes=None):
3 """Initialise un étudiant avec un nom et une liste de notes (défaut
: vide)."""
4 [Link] = nom
5 [Link] = notes if notes is not None else []
6
7 if __name__ == "__main__":
8 etudiant1 = Etudiant("Alice")
9 etudiant2 = Etudiant("Bob")
10
11 [Link](15)
12 print(f"Notes d'Alice : {[Link]}")
13 print(f"Notes de Bob : {[Link]}")
Ce code garantit que chaque étudiant a sa propre liste de notes, évitant les effets secondaires.
Pour approfondir la compréhension du constructeur et des classes, consultez la documentation
officielle de Python sur les classes 1 .
8.3 Méthodes
Comme évoqué au début de ce chapitre, une classe ne se limite pas à stocker des données : elle peut
également définir des comportements, c’est-à-dire des actions que les objets peuvent effectuer. En
programmation orientée objet, ces comportements sont implémentés à l’aide de méthodes qui sont
des fonctions définies à l’intérieur d’une classe. Il existe quatre principaux types de méthodes en
Python : les méthodes d’instance qui opèrent sur un objet spécifique (comme celles que nous avons
déjà utilisées dans les exemples précédents) ; les méthodes de classe qui agissent sur la classe elle-
même ; les méthodes statiques qui sont des fonctions utilitaires liées à la classe mais indépendantes
des objets ou de la classe ; et les méthodes spéciales qui personnalisent le comportement des objets
dans des contextes spécifiques.
Une méthode est donc une fonction définie à l’intérieur d’une classe qui décrit un comportement
ou une action associée à la classe ou à ses objets. Les méthodes se divisent en quatre catégories :
• Méthodes d’instance : Liées à un objet spécifique, elles utilisent le paramètre self pour
accéder aux attributs et autres méthodes de cet objet.
• Méthodes de classe : Liées à la classe elle-même, elles utilisent le paramètre cls et le
1. [Link]
décorateur @classmethod pour manipuler des données communes à tous les objets.
• Méthodes statiques : Indépendantes des objets et de la classe, elles utilisent le décorateur
@staticmethod et ne prennent ni self ni cls. Elles servent à des opérations utilitaires liées
thématiquement à la classe.
• Méthodes spéciales : Identifiables par leurs doubles tirets bas (par exemple, __init__,
__str__), elles personnalisent le comportement des objets pour des opérations spécifiques,
comme l’affichage ou les calculs mathématiques.
Cette section se concentre sur les méthodes d’instance, qui sont les plus courantes, et sur la
méthode spéciale __str__ qui améliore l’affichage des objets. D’autres méthodes spéciales, comme
__call__ (pour rendre un objet « appelable » comme une fonction) ou des méthodes mathématiques
(__add__, __mul__, etc.), ainsi que les méthodes de classe et statiques, peuvent être explorées via
la documentation officielle de Python sur les classes et sur les méthodes spéciales 2 ou sur Real
Python(classes 3 , méthodes spéciales 4 ).
Une méthode d’instance peut appeler d’autres méthodes de la même classe via self, ce qui
permet de composer des comportements complexes à partir de tâches plus simples. Cette approche,
appelée composition, rend le code modulaire. De plus, les méthodes d’instance peuvent retourner
des résultats de différents types (chaînes, nombres, booléens) pour fournir des informations ou
déclencher des actions ou ne rien retourner (None) si elles se contentent de modifier l’état de l’objet.
Voici une illustration avec une classe CompteBancaire :
1 class CompteBancaire:
2 def __init__(self, titulaire, solde):
3 """Initialise un compte bancaire avec un titulaire et un solde
initial."""
4 [Link] = titulaire
5 [Link] = solde
6
7 def deposer(self, montant):
8 """Ajoute le montant spécifié au solde, si positif."""
9 if montant > 0:
10 [Link] += montant
11 return f"Dépôt de {montant} effectué. Nouveau solde : {self.
solde}"
12 return "Erreur : le montant doit être positif."
13
14 def peut_retirer(self, montant):
15 """Vérifie si un retrait est possible (retourne un booléen)."""
2. [Link]
3. [Link]
4. [Link]
True
Retrait de 500 effectué. Nouveau solde : 500
Erreur : retrait impossible.
Dépôt de 100 effectué. Nouveau solde : 600
Dans cet exemple, peut_retirer() retourne un booléen pour indiquer si un retrait est possible,
tandis que retirer() modifie le solde et retourne une chaîne décrivant l’action. Cette variété de
retours illustre la polyvalence des méthodes d’instance. La composition des méthodes favorise la
réutilisabilité du code, car une méthode comme peut_retirer() peut être utilisée seule ou dans
d’autres méthodes. Cela reflète la modularité des fonctions, mais appliquée aux objets.
Note. Une méthode qui ne retourne rien explicitement (pas de return) renvoie None par défaut. Si
vous attendez un résultat spécifique, assurez-vous que la méthode inclut une instruction return
avec la valeur appropriée.
Les méthodes d’instance peuvent accepter plusieurs paramètres pour interagir avec des données
externes, comme d’autres objets ou des valeurs fournies par l’utilisateur. Cela permet de modéliser
des relations ou des comparaisons entre objets.
Voici une classe Rectangle avec une méthode comparant deux rectangles :
1 class Rectangle:
2 def __init__(self, longueur, largeur):
3 """Initialise un rectangle avec une longueur et une largeur."""
4 [Link] = longueur
5 [Link] = largeur
6
7 def calculer_aire(self):
8 """Calcule l'aire du rectangle."""
9 return [Link] * [Link]
10
11 def est_plus_grand(self, autre_rectangle):
12 """Vérifie si ce rectangle a une aire plus grande qu'un autre."""
13 return self.calculer_aire() > autre_rectangle.calculer_aire()
14
15 if __name__ == "__main__":
16 rectangle1 = Rectangle(5, 3)
17 rectangle2 = Rectangle(2, 4)
18
19 print(f"Aire de rectangle1 : {rectangle1.calculer_aire()}")
20 print(f"Aire de rectangle2 : {rectangle2.calculer_aire()}")
21 print(f"rectangle1 est plus grand : {rectangle1.est_plus_grand(
rectangle2)}")
Aire de rectangle1 : 15
Aire de rectangle2 : 8
rectangle1 est plus grand : True
Cet affichage technique ne révèle rien sur l’état de l’objet. Ajoutons __str__ pour personnaliser la
représentation :
1 class Personne:
2 def __init__(self, nom, age):
3 """Initialise une personne avec un nom et un âge."""
4 [Link] = nom
5 [Link] = age
6
7 def __str__(self):
8 """Retourne une représentation textuelle de la personne."""
9 return f"{[Link]}, {[Link]} ans"
10
11 if __name__ == "__main__":
12 personne = Personne("Alice", 18)
13
14 print(personne)
15 print(f"Personne : {personne}")
Alice, 18 ans
Personne : Alice, 18 ans
Avec __str__, l’affichage devient intuitif, montrant les attributs nom et age de l’objet de manière
lisible. Cet exemple illustre comment __str__ améliore l’expérience utilisateur en rendant les
informations de l’objet immédiatement compréhensibles.
Note. La méthode __str__ doit impérativement retourner une chaîne de caractères (type str
). Retourner un autre type, comme un entier (return [Link]) ou une liste, provoque une
TypeError lorsque print(), une f-string ou str() est utilisé. Assurez-vous que le résultat est une
chaîne, par exemple en utilisant une f-string ou la fonction str() pour convertir les valeurs.
La classe dérivée a automatiquement accès à tous les attributs et méthodes de la classe de base,
comme si elles étaient définies dans la classe dérivée elle-même. Cependant, pour initialiser
correctement les attributs hérités, le constructeur __init__ de la classe dérivée doit souvent appeler
celui de la classe de base à l’aide de la fonction super().
Voici un exemple simple avec une classe Personne (base) et une classe Etudiant (dérivée) :
1 class Personne:
2 def __init__(self, nom, age):
3 """Initialise une personne avec un nom et un âge."""
4 [Link] = nom
5 [Link] = age
6
7 def se_presenter(self):
8 """Retourne une présentation de la personne."""
9 return f"Je m'appelle {[Link]} et j'ai {[Link]} ans."
10
11 class Etudiant(Personne):
12 def __init__(self, nom, age, numero_matricule):
13 """Initialise un étudiant avec un nom, un âge et un numéro matricule
."""
14 super().__init__(nom, age) # Appelle le constructeur de Personne
15 self.numero_matricule = numero_matricule
16
17 if __name__ == "__main__":
18 etudiant = Etudiant("Alice", 18, "E12345")
19
20 print(etudiant.se_presenter())
21 print(f"Numéro matricule : {etudiant.numero_matricule}")
Etudiant hérite de Personne en réutilisant la méthode se_presenter et les attributs nom et age.
Le constructeur de Etudiant appelle super().__init__(nom, age) pour initialiser les attributs
hérités, puis ajoute l’attribut spécifique numero_matricule. Cela illustre comment l’héritage permet
d’étendre une classe existante sans dupliquer le code.
Note. Oublier d’appeler le constructeur de la classe de base avec super().__init__(...) peut
laisser les attributs hérités non initialisés, entraînant des erreurs comme AttributeError lorsque
vous essayez d’accéder à ces attributs. Par exemple, si Etudiant ne définit pas [Link] via
super(), se_presenter() échouera.
7 def calculer_aire(self):
8 """Calcule l'aire du rectangle."""
9 return [Link] * [Link]
10
11 def calculer_perimetre(self):
12 """Calcule le périmètre du rectangle."""
13 return 2 * ([Link] + [Link])
14
15 def __str__(self):
16 """Retourne une représentation textuelle du rectangle."""
17 return f"Rectangle de {[Link]} x {[Link]}"
18
19 class Carre(Rectangle):
20 def __init__(self, cote):
21 """Initialise un carré avec un côté."""
22 super().__init__(cote, cote) # Un carré est un rectangle avec
longueur = largeur
23
24 if __name__ == "__main__":
25 rectangle = Rectangle(5, 3)
26 carre = Carre(4)
27
28 print(rectangle)
29 print(f"Aire du rectangle : {rectangle.calculer_aire()}")
30 print(f"Périmètre du rectangle : {rectangle.calculer_perimetre()}")
31 print(carre)
32 print(f"Aire du carré : {carre.calculer_aire()}")
33 print(f"Périmètre du carré : {carre.calculer_perimetre()}")
Rectangle de 5 x 3
Aire du rectangle : 15
Périmètre du rectangle : 16
Rectangle de 4 x 4
Aire du carré : 16
Périmètre du carré : 16
Dans cet exemple, Carre hérite de Rectangle et réutilise ses méthodes calculer_aire(), calculer_perimetre
() et __str__. Le constructeur de Carre appelle super().__init__(cote, cote) pour initialiser
les attributs longueur et largeur avec la même valeur, reflétant la contrainte d’un carré. Cela
montre comment l’héritage permet à Carre de bénéficier des fonctionnalités de Rectangle sans
redéfinir les méthodes.
Note. La classe Carre est une spécialisation de Rectangle, car elle impose une contrainte sup-
plémentaire (longueur = largeur). L’héritage est utile pour modéliser ce type de relations, où une
classe dérivée est un cas particulier de la classe de base.
Pour redéfinir une méthode, vous déclarez une méthode avec le même nom dans la classe dérivée. Si
nécessaire, vous pouvez appeler la méthode de la classe de base à l’aide de super() pour combiner
les comportements.
Modifions Carre pour redéfinir __str__ et ajouter une méthode spécifique :
1 class Carre(Rectangle):
2 def __init__(self, cote):
3 """Initialise un carré avec un côté."""
4 super().__init__(cote, cote)
5 [Link] = cote # Stocke le côté pour usage spécifique
6
7 def __str__(self):
8 """Retourne une représentation textuelle du carré."""
9 return f"Carré de côté {[Link]}"
10
11 def est_carre(self):
12 """Confirme que l'objet est un carré."""
13 return True
14
15 if __name__ == "__main__":
16 rectangle = Rectangle(5, 3)
17 carre = Carre(4)
18
19 print(rectangle)
20 print(carre)
21 print(f"Aire du carré : {carre.calculer_aire()}")
22 print(f"Périmètre du carré : {carre.calculer_perimetre()}")
23 print(f"Est un carré ? {carre.est_carre()}")
Rectangle de 5 x 3
Carré de côté 4
Aire du carré : 16
Périmètre du carré : 16
Est un carré ? True
La classe Carre redéfinit __str__ pour afficher Carré de côté au lieu de Rectangle de longueur
x largeur, cela offre une description plus spécifique. Les méthodes calculer_aire() et calculer_perimetre
() sont héritées sans modification, tandis que est_carre est une nouvelle méthode propre à Carre.
Cela illustre comment une classe dérivée peut personnaliser les comportements hérités tout en
ajoutant des fonctionnalités uniques.
Note. Lors de la redéfinition d’une méthode, assurez-vous que la nouvelle version respecte l’objectif
de la méthode originale. Par exemple, __str__ doit toujours retourner une chaîne de caractères.
Une redéfinition incorrecte, comme retourner un entier, provoquerait des erreurs dans les contextes
où la méthode est utilisée.
5. [Link]