Système d`Information et programmation

publicité
Système d'Information et programmation
Programmation Python
Manipulation de données
http://www.agroparistech.fr/Donnees-et-Programmation.html
Christine MARTIN
UFR d'Informatique
Département MMIP
[email protected]
AgroParisTech Massy 1A apprentis
Année 2015-2016
2
Table des matières
1
2
3
Introduction ................................................................................................................................5
1.1
Contexte, organisation et objectifs du module .....................................................................5
1.2
Choix du langage de programmation : pourquoi Python ......................................................5
1.3
Installer Python ...................................................................................................................6
Premiers programmes .................................................................................................................7
2.1
Environnement de développement......................................................................................7
2.2
Un exemple .........................................................................................................................8
Premiers pas en Python............................................................................................................. 10
3.1
4
5
3.1.1
Définitions et syntaxe ................................................................................................ 10
3.1.2
Les types prédéfinis ................................................................................................... 10
3.1.3
Conversion de types................................................................................................... 11
3.1.4
Variables et affectation (ou assignation) .................................................................... 12
3.1.5
Afficher la valeur d'une ou plusieurs variables ............................................................ 12
3.1.6
Opérateurs et expressions ......................................................................................... 13
3.2
Interactions avec l'utilisateur : les fonctions input() et raw_input() .................................... 15
3.3
Sélection ou exécution conditionnelle ............................................................................... 16
3.4
Instructions et blocs .......................................................................................................... 17
3.5
Les fonctions ..................................................................................................................... 18
3.6
Importer un module de fonctions ...................................................................................... 22
3.7
Structure générale d'un script Python ................................................................................ 25
Boucles et séquences ................................................................................................................ 27
4.1
Répétitions en boucle - l'instruction while ......................................................................... 27
4.2
Les séquences.................................................................................................................... 29
4.3
Utilisation des chaînes de caractères ................................................................................. 30
4.4
Les listes ............................................................................................................................ 35
4.5
Conversions liste – chaîne de caractères ............................................................................ 36
4.6
Retour sur l'affectation ...................................................................................................... 39
Programmation de graphiques - séquences ............................................................................... 41
5.1
6
Données, types et variables ............................................................................................... 10
Présentation des bibliothèques ......................................................................................... 41
5.1.1
La bibliothèque random ............................................................................................. 41
5.1.2
La bibliothèque matplotlib ......................................................................................... 42
Manipulation des Fichiers ......................................................................................................... 57
3
6.1
Ouvrir un fichier ................................................................................................................ 57
6.2
Fermer un fichier ............................................................................................................... 57
6.3
Méthodes de lecture ......................................................................................................... 57
6.4
Méthodes d’écriture : ........................................................................................................ 58
6.5
Méthodes seek et tell ....................................................................................................... 58
6.6
Mise en pratique ............................................................................................................... 59
7
Programmation de graphique - fichiers ..................................................................................... 61
8
Les bases de données et le langage SQL .................................................................................... 63
8.1
Quelques définitions.......................................................................................................... 64
8.2
La notion de clé ................................................................................................................. 67
8.2.1
Clé primaire ............................................................................................................... 67
8.2.2
Clé étrangère ............................................................................................................. 67
8.3
Contraintes d'intégrité ....................................................................................................... 68
8.4
Schéma et contenu ............................................................................................................ 69
8.5
Le langage SQL (Structured Query Language) ..................................................................... 71
9
8.5.1
Consulter les données stockées dans une base de données existante ........................ 71
8.5.2
Ajouter des données dans une table .......................................................................... 82
8.5.3
Supprimer des données dans une table ...................................................................... 83
8.5.4
Modifier le contenu d'une table ................................................................................. 83
8.5.5
Créer une base de données ........................................................................................ 86
8.5.6
Créer / Supprimer/ Modifier la structure d'une table ................................................. 86
Interaction avec des bases de données en Python ..................................................................... 89
9.1
Se connecter à une base de données SQLite en Python...................................................... 89
9.2
Interroger une base de données SQLite en Python............................................................. 90
9.3
Interrogation contextuelle ................................................................................................. 91
9.4
Se déconnecter d'une base de données SQLite en Python ................................................. 91
9.5
Insertions et suppressions ................................................................................................. 93
9.6
Création du schéma d'une base de données depuis un programme Python ....................... 94
10
Projet .................................................................................................................................... 95
4
Séance 1
1 Introduction
1.1 Contexte, organisation et objectifs du module
Issu des domaines de l'informatique et des télécommunications, le concept de Système
d’Information a envahi l'ensemble des organisations privées ou publiques quel que soit leur domaine
d’intérêt. Le terme système d'information (ou SI) est notamment défini comme un ensemble
organisé de ressources (personnel, données, procédures, matériel, logiciel, ...) permettant d'acquérir,
de stocker, de structurer et de communiquer des informations (de formats divers) nécessaires au
bon fonctionnement de l’organisme concerné. Connaître, comprendre, savoir utiliser voire créer de
tels systèmes est désormais indispensable à tout ingénieur.
Lors de ce module, vous apprendrez les bases de la programmation dans un des langages
informatiques les plus utilisés à l'heure actuelle (Python) et comment un programme peut exploiter
des données de différentes provenances notamment de bases de données (outils au cœur des
systèmes d'information) que nous définirons à cette occasion.
Ce module vous apportera des connaissances tantôt génériques tantôt plus spécifiques et
indispensables à tout futur ingénieur et notamment vous apprendra à :





structurer, modéliser, interroger ses données,
décomposer un problème,
définir l'algorithme résolvant un problème précis,
implémenter un algorithme dans un langage donné,
présenter des résultats.
Ce module se compose de 27h d'enseignement réparties en 9 séances de 3h. Les 7 premières
séances seront consacrées à du Cours/ TD tandis que les 2 dernières permettront la réalisation d'un
projet en binôme sur lequel vous serez évalués.
1.2 Choix du langage de programmation : pourquoi Python
Les avantages de Python sont nombreux, c’est un langage :
 facile à apprendre, à lire, à comprendre et à écrire ;
 avec une syntaxe sobre ;
 portable (fonctionne sous de nombreux systèmes d'exploitation) ;
 dynamique ;
 extensible ;
 gratuit ;
 qui permet (sans l'imposer)
o une approche modulaire (découpage d'un programme en sous-unités) ;
5
o
une approche orientée objet de la programmation (possibilité de définir des entités
spécifiques aux besoins d'une application donnée).
Développé depuis 1989 par Guido van Rossum et de nombreux contributeurs bénévoles, une des
forces de Python est d'être étendu et maintenu par une communauté très dynamique donnant ainsi
accès à de nombreuses bibliothèques adaptées à des besoins spécifiques :
• Calcul numérique ;
• Analyse de données ;
• Traitement d’images ;
• Bioinformatique ;
• …
Vous pourrez trouver un index des bibliothèques disponibles à l'adresse suivante :
https://pypi.python.org/pypi
Des éléments d'installation pour Windows sont par ailleurs accessibles ici :
http://www.lfd.uci.edu/~gohlke/pythonlibs/
Le dynamisme de cette communauté se manifeste également par la tenue de plusieurs conférences
annuelles et notamment la PyCon (internationale) : http://www.pycon.fr/2015/
Ses différentes qualités lui valent d'être parmi les langages les plus utilisés actuellement que ce soit
dans l'Industrie ou le secteur public et la recherche.
Des sociétés que vous connaissez bien telles que Google, Amazon, Facebook ou encore Dropbox
réalisent au moins une partie de leurs développements informatiques en langage Python.
Python présente enfin la particularité de pouvoir être utilisé de plusieurs manières différentes. En
mode interactif, c'est-à-dire d'une manière telle que l'on peut dialoguer avec lui directement depuis
le clavier, cela peut permettre de découvrir et tester un grand nombre de fonctionnalités du langage.
Ou plus classiquement, il est possible de créer des scripts (fichiers contenant les instructions à
réaliser), de les sauvegarder sur disque et de les faire exécuter.
1.3 Installer Python
Il existe différentes versions de Python organisées en deux "lignées", nommées 2.x et 3.y. Plus x est
grand (respectivement y) et plus la version en question de la lignée 2 (respectivement 3) est récente.
Les deux lignées cohabitent à l'heure actuelle et certainement encore pour quelques années le temps
que les programmes conçus en lignée 2 soient portés pour la lignée 3. Bien que la lignée 2 soit vouée
à disparaître petit à petit, de nombreux programmes sont encore développés en Python 2.x et
notamment dans l'industrie. En effet, le coût de portage d'un programme est souvent non
négligeable.
Pour ce module nous avons donc choisi d'utiliser la version 2.7 de Python (dernière version de lignée
2).
Python est de manière générale facile à installer mais pour simplifier encore les choses, il existe
différentes distributions qui proposent en plus du cœur de Python de nombreuses bibliothèques très
utiles.
6
Nous utiliserons ici la distribution Anaconda (https://store.continuum.io/) qui est libre et va nous
fournir les différentes librairies que nous allons utiliser ainsi qu'un environnement de développement
convivial et performant nommé Spyder (https://github.com/spyder-ide).
Etant libre, vous pouvez facilement installer cette distribution sur votre ordinateur personnel. Il
existe des versions pour les différents systèmes d'exploitation. Vous trouverez toutes les
informations nécessaires sur leur site web : https://store.continuum.io/
2 Premiers programmes
2.1 Environnement de développement
Il existe différents environnements de développement liés au langage Python. Pour ce module, nous
avons choisi d'utiliser le logiciel Spyder (https://github.com/spyder-ide) qui est à la fois facile à
prendre en main et présente des caractéristiques satisfaisantes.
Figure 1 : Fenêtre principale de Spyder au lancement de l'application
Il permet notamment dans un formalisme assez léger d'éditer et de faire exécuter nos programmes
au sein d'une unique application.
Configuration de Spyder
Pour simplifier l'execution de vos scripts, allez dans Outils > Préférences > Executer
Et comme indiqué dans la Figure 2 activez le bouton Exécuter dans une nouvelle console Python
dédiée puis cliquez sur Apply et enfin sur OK.
Désormais pour exécuter un script Python il vous suffira de placer votre curseur dans la zone
d'édition (cf. Figure 1) puis d'actionner la touche F5.
Cela ouvrira alors, comme nous verrons dans la section suivante, un nouvel onglet dédié au script
considéré dans la zone d'exécution (en violet dans la Figure 1)
7
Figure 2 : Menu Outils > Préférences
2.2 Un exemple
Un programme (script) est retranscrit dans un fichier texte qui pourra être enregistré et exécuté à la
demande.
Pour cela nous allons utiliser la zone d'éditeur de Spyder matérialisée en orange dans la Figure 1.
À l'aide du menu Fichier, ouvrez le script arithmetique.py.
Dans la zone d'édition de Spyder nous devez voir apparaître un nouvel onglet portant le nom du
script concerné et les instructions qu'il contient comme dans la Figure 3.
Figure 3 : Premier script
Demandez ensuite son exécution en pressant la touche F5.
Si la configuration précédente a bien été effectuée, pour notre programme arithmetique.py nous
obtenons dans la zone d'exécution le résultat présenté en Figure 4.
8
Figure 4 : Résultat de l'execution du script arithmetique.py
Exercice 1
Analysons un peu le résultat produit par notre script.
À quelles instructions correspondent les valeurs présentes dans la zone de résultat ?
Que pouvez-vous en déduire sur les différentes instructions présentes dans le script considéré et leur
ordre d'exécution ?
Que signifie 8. ?
Que pouvez-vous en déduire sur les opérateurs mathématiques utilisés ?
Quel est le rôle de l'instruction print ?
Remarque :
Un programme source doit être lisible pour un être humain et donc judicieusement "commenté" afin
d'expliquer en langage naturel ses parties non triviales.
Un commentaire en Python est précédé de : #
Un DocString (documentation d'un élément de programme) se place entre """ """ .
Nous reviendrons sur cette notion un peu plus tard.
9
Exemple :
3 Premiers pas en Python
3.1 Données, types et variables
3.1.1
Définitions et syntaxe
Tout programme pour produire un résultat utilise des valeurs qui correspondent à des données de
différentes natures ou types (nombres entiers ou réels, du texte, ...) sur lesquels il va réaliser des
opérations créant ainsi de nouvelles valeurs jusqu'à l'obtention du résultat désiré.
Lors de ce processus, les valeurs sont stockées en mémoire et rattachées à ce que l'on appelle des
variables par un processus dit d'affectation.
Sous Python, les noms de variables doivent obéir à quelques règles simples :
- Un nom de variable est une séquence de lettres (a - z, A - Z) et de chiffres (0 - 9), qui doit
toujours commencer par une lettre.
- Seules les lettres ordinaires sont autorisées. Les lettres accentuées, les cédilles, les espaces,
les caractères spéciaux tels que $, #, @, etc. sont interdits, à l'exception du caractère _
(souligné).
- La casse est significative (les caractères majuscules et minuscules sont distingués).
Les noms doivent être différents des mots réservés du langage (liste non exhaustive) :
and
def
finally
in
print
yield
as
del
for
is
raise
None
assert
elif
from
lambda
return
True
break
else
global
not
try
False
class
except
if
or
while
continue
exec
import
pass
with
3.1.2
Les types prédéfinis
Pour distinguer les divers contenus possibles, le langage de programmation fait usage de différents
types de variables prédéfinis :
-
le type 'entier' : int ;
10
-
3.1.3
le type 'réel' : float ;
le type 'booléen' (vrai ou faux) : bool ;
le type 'chaîne de caractères' (texte) : string ;
o En Python, une donnée de type string est une suite quelconque de caractères
délimitée soit par des apostrophes (simple quotes), soit par des guillemets (double
quotes).
o Une chaîne délimitée par des apostrophes peut contenir des guillemets et vice versa.
o La séquence \' permet d'insérer une apostrophe dans une chaîne délimitée par des
apostrophes.
o La séquence \n dans une chaîne provoque un saut à la ligne.
le type 'liste' (succession ordonnée de valeurs) : list ;
etc.
Conversion de types
En Python, il est utile parfois de préciser, de façon explicite, le type de l’expression utilisée :
 int(expression) indique que expression doit être considérée comme un entier ;
 float(expression) indique que expression doit être considérée comme un réel ;
 str(expression) indique que expression doit être considérée comme une chaîne de
caractères.
Exemple : int(3.2) est égal à 3.
Exercice 2 :

Donnez la valeur et le type de chacune des conversions suivantes :
Valeur
Type
float(10)
float(3)/float(2)
float(3)/int(2)
str(10)
int(float(3)/float(2))
float(int(3.)/int(2.))
int(10)
int(3.)/float(2)
11
3.1.4
Variables et affectation (ou assignation)
En Python, les variables sont déclarées à la volée sans précision de type. Le type d’une variable est
déduit lors de son affectation. Comme dans de nombreux autres langages, l'opération d'affectation
est représentée par le signe '=' :
Exemple :
a = 2 #La variable a reçoit la valeur 2 et est donc de type 'entier'
Tout ce qui est noté après le symbole # n'est pas analysé par Python. C'est ce que l'on appelle un
"commentaire" texte qui permet d'expliciter l'élément auquel il se rapporte.
Exercice 3 : Votre premier script
Rédigez le script ci-dessous dans un fichier hello.py :
texte_a_afficher = "Hello World !"
print texte_a_afficher
# affichage du texte
Testez ce script.
La valeur d’une variable peut être modifiée. Sa valeur antérieure est alors perdue.
a = a + 1
a = a - 1
# 3 (incrémentation)
# 2 (décrémentation)
Outre l'affectation simple, on peut aussi utiliser les formes suivantes :
a = 4
a += 2
a -= 3
c = d = 8
e, f = 2.7, 5.1
e, f = f, e
3.1.5
#
#
#
#
#
#
#
forme de base
équivalent à : a = a + 2 si a est déjà référencé,
provoquera une erreur sinon
équivalent à : a = a-3 si a est déjà référencé
cibles multiples (affectation de droite à gauche)
affectation par position
échange les valeurs de e et f
Afficher la valeur d'une ou plusieurs variables
Comme vu précédemment, pour afficher une valeur (ou plusieurs) valeurs à l'écran, nous disposons
de l'instruction print.
Cette instruction permet également d'afficher la valeur stockée dans une variable si son type le
permet.
Lorsque l'on souhaite afficher plusieurs éléments par une unique instruction, ces éléments peuvent
être séparés par des virgules. Si une virgule est placée en fin d'instruction cela empêche le retour à la
ligne.
12
Exercice 4 :
On considère le script print_vars.py.
Quelles sont les variables déclarées dans ce script et de quel type sont-elles ?
Faites exécuter ce script et analysez le résultat produit.
Exercice 5 :
Créez un nouveau script que vous nommerez priority.py et dans lequel vous assignerez les valeurs
respectives 3, 5, 7 à trois variables a, b, c.
Votre script devra permettre ensuite d'afficher le résultat de l'opération a - b/c.
Le résultat est-il mathématiquement correct ?
Qu'en déduisez-vous sur le fonctionnement des opérateurs mathématiques ?
3.1.6
Opérateurs et expressions
Les opérateurs Python ne sont pas seulement les quatre opérateurs mathématiques de base (*, +, et /).
Il faut leur ajouter l'opérateur ** pour l'exponentiation (mise à la puissance x), ainsi qu'un certain
nombre d'opérateurs logiques, des opérateurs agissant sur les chaînes de caractères, des opérateurs
effectuant des tests d'identité ou d'appartenance, etc.
Signalons au passage la disponibilité de l'opérateur modulo, représenté par le symbole %. Cet
opérateur fournit le reste de la division entière d'un nombre par un autre.
Exercice 6 :
Testez et analysez le contenu du script cercle.py.
Quelle est, à votre avis, l'utilité de la fonction type() ?
13
Opérateurs de comparaison
Python dispose des opérateurs de comparaison suivants :
x==y
x est égal à y
x != y
x > y
x est plus grand que y
x < y
x >= y
x est plus grand que, ou égal à y
x <= y
x est différent de y
x est plus petit que y
x est plus petit que, ou égal à y
La réduction d'une comparaison est de type booléen c'est-à-dire que cela vaut soit vrai (True) soit
faux (False).
Attention :
Ne pas confondre :
 Affectation : =
 Comparaison : ==
L’affectation a un effet sur les variables concernées mais n’a pas de valeur après réduction.
La comparaison n’a pas d’effet sur les variables comparées mais a une valeur après réduction qui est
de type booléen.
b=1
a=b
# a reçoit b
print a == b
# a et b ne sont pas modifiées
# affichera True
Opérateurs logiques
Il existe également des opérateurs logiques c'est-à-dire qui agissent sur des booléens.
En Python, il s'agit de :
x and y
le "et" logique
Vrai si x et y sont vrais en même temps et faux sinon
x or y
le "ou" logique
Vrai si x ou y sont vrais indépendamment l'un de l'autre et faux sinon
not x
la négation
Vrai si x est faux et vice versa
Priorité des opérations
Lorsqu'il y a plus d'un opérateur dans une expression, l'ordre dans lequel les opérations doivent être
effectuées dépend de règles de priorité. Sous Python, les règles de priorité des opérateurs
arithmétiques sont les mêmes que celles qui vous ont été enseignées en mathématiques.
Les opérateurs arithmétiques sont prioritaires sur les opérateurs de comparaison qui sont euxmêmes prioritaires sur les opérateurs logiques.
14
Exercice 7 :
Quelle est la valeur et le type des expressions suivantes ?
Valeur
Type
5 + 3/2
5. + 3/2
int(5.+3/2)
float(5+3 % 2)
5 + 3 % 2
5 + 3./2
int(5+3./2)
5/2. + float(2**3 -1)
4 < 2 or 5 < 7
'123' == 123
int('123') == 123
int(int('123') == 123)
'au revoir' != False
3.2 Interactions avec l'utilisateur : les fonctions input() et raw_input()
La plupart des scripts élaborés nécessitent à un moment ou l'autre une intervention de l'utilisateur
(entrée d'un paramètre, clic de souris sur un bouton, etc.). Dans un script simple en mode texte
(comme ceux que nous avons créés jusqu'à présent), la méthode la plus simple consiste à employer
la fonction intégrée input(). Cette fonction provoque une interruption dans le programme courant.
L'utilisateur est invité à entrer des caractères au clavier et à terminer avec <Enter>. Lorsque cette
touche est enfoncée, l'exécution du programme se poursuit, et la fonction fournit en retour une
valeur correspondant à ce que l'utilisateur a entré.
Cette valeur peut alors être assignée à une variable choisie.
Remarques importantes :
La fonction input() renvoie une valeur dont le type correspondant à ce que l'utilisateur a entré.
Pour cette raison, il sera souvent préférable d'utiliser dans vos scripts la fonction similaire
raw_input(), laquelle renvoie toujours une chaîne de caractères. Vous pouvez ensuite convertir cette
chaîne en nombre à l'aide de int() ou de float().
Exemple :
15
a = raw_input('Entrez
print type(a)
#
b = float(a)
#
print type(b)
#
une donnée : ')
affiche <type 'str'>
conversion en valeur numérique
affiche <type 'float'>
3.3 Sélection ou exécution conditionnelle
Il arrive fréquemment en programmation que l'on souhaite réaliser certains traitements dans
certains cas et éventuellement d'autres dans d'autres circonstances.
Pour cela, nous disposons en Python de l'instruction if.
Considérons le script :
a = 150
if (a > 100):
print "a dépasse la centaine"
print "nous sommes sortis de la condition"
La première instruction affecte la valeur 150 à la variable a. Jusqu'ici rien de nouveau.
À la deuxième ligne, constatez en revanche la présence d'un nouveau mot-clé if et le retrait vers la
droite des écritures de la troisième ligne.
Cela signifie que vous êtes entré dans ce que l'on appelle un bloc d’instructions. L'instruction
commençant par le mot clé if est appelé entête de bloc.
Tant que vous voulez que les instructions suivantes soient effectuées sous la condition « if (a >
100): » (c'est-à-dire si la variable a contient une valeur strictement supérieure à 100) il faudra les
faire précéder d’une tabulation (ou de 4 espaces).
Dans le cas contraire, pour indiquer que vous sortez de ce bloc d’instruction, il faut vous
repositionner au même niveau que l'entête du bloc que vous souhaitez quitter de manière analogue
à l'instruction en quatrième ligne de notre script précédent.
Exercice 8 :
Ouvrez et exécutez le script condition.py.
Le résultat obtenu est-il conforme à votre attente ?
Modifiez ce script pour attribuer à a la valeur 20. Exécutez à nouveau votre script.
Que constatez-vous ?
Modifiez à nouveau votre script comme suit :
a = 20
if (a > 100):
print "a dépasse la centaine"
else:
print "a ne dépasse pas cent"
Qu'en déduisez-vous sur le sens du mot clé else ?
16
Remarque :
En Python, vous devez utiliser les sauts à la ligne et l'indentation, mais en contrepartie vous n'avez
pas à vous préoccuper d'autres symboles délimiteurs de blocs. En définitive, Python vous "force" à
écrire du code lisible (où les blocs d'instructions et leur organisation apparaissent clairement), et à
prendre de bonnes habitudes que vous conserverez lorsque vous utiliserez d'autres langages.
Le mot clé elif
Lorsque l'on veut prendre en compte davantage d'alternatives on utilise la syntaxe suivante :
if -- [elif] -- [else]
Exemple :
Cas particulier :
Test d'une valeur booléenne :
if x :
# mieux que (if x is True:)
# ou que (if x == True:)
Exercice 9 :
Écrire un programme divise.py qui demande à l'utilisateur deux nombres a et b et affiche "oui" si a
divise b ou b divise a et "non" sinon. Pensez à utiliser l'opérateur modulo.
3.4 Instructions et blocs
Comme nous le verrons par la suite, d'autres éléments de langage permettent de créer des blocs
d'instructions. Quels que soient ces éléments que nous détaillerons par la suite (boucles, fonctions,
...) la syntaxe à adopter reste la même.
Instruction composée = En-tête , double point , bloc d'instructions indenté
Ainsi, l’indentation détermine les débuts et fin de blocs, l'entête de bloc qui se termine par « : »
détermine dans quels cas de figure le bloc sera exécuté ou non.
On peut imbriquer des blocs pour réaliser des structures de décision complexes.
Le schéma ci-contre en résume le principe.
17
Les blocs d'instructions sont toujours associés à une ligne d'en-tête contenant une instruction bien
spécifique (if, elif, else, while, def, ...) se terminant par un double point.
Les blocs sont délimités par l'indentation : toutes les lignes d'un même bloc doivent être indentées
exactement de la même manière (c'est-à-dire décalées vers la droite d'un même nombre d'espaces).
Le nombre d'espaces à utiliser pour l'indentation est quelconque, mais la plupart des programmeurs
utilisent des multiples de 4.
Notez que le code du bloc le plus externe (bloc 1) ne peut pas lui-même être écarté de la marge de
gauche (Il n'est imbriqué dans rien).
Les espaces et les commentaires sont normalement ignorés à part ceux qui servent à l'indentation,
en début de ligne, les espaces placés à l'intérieur des instructions et des expressions sont presque
toujours ignorés (sauf s'ils font partie d'une chaîne de caractères). Il en va de même pour les
commentaires : ceux-ci commencent toujours par un caractère dièse (#) et s'étendent jusqu'à la fin
de la ligne courante.
Exercice 10 :
Écrire un script compare_2.py qui compare deux nombres. Votre programme affichera 1 si le premier
est strictement plus grand que le deuxième, -1 dans le cas contraire et 0 s'ils sont égaux.
Exercice 11 :
Écrire un script classe_3.py qui classe trois nombres dans l'ordre croissant. Les données
alphanumériques
3.5 Les fonctions
Motivations
Pour effectuer une même série de tâches à des endroits différents du programme, il faudrait a priori
copier ce code plusieurs fois.
Pour illustrer ces propos, voici un petit programme destiné à chercher le maximum parmi trois
triplets de nombres entrés successivement par l'utilisateur, toutes séries de nombres confondues :
18
La recherche du max d'un triplet est réutilisée plusieurs fois : 3 fois pour les triplets utilisateur, et 1
fois pour le résultat global.
Définition
Un moyen de synthétiser le code précédent est de créer une fonction c'est-à-dire un ensemble
d'instructions regroupées sous un nom et permettant d'effectuer à la demande (appel) la série
d'actions correspondante, à l'aide éventuellement de paramètres d'entrée (valeurs représentées par
des variables et nécessaires à l'exécution de sa tâche), et "retourne à celui qui l’a appelée" le résultat
à l'aide de l'instruction return.
Les fonctions sont les éléments structurants de base de tout langage procédural.
La définition d'une fonction se fait à l'aide de l'instruction def, suivie du nom de la fonction, et de la
liste des paramètres entre parenthèses.
def nom_fonction(parametres):
"""Documentation de la fonction."""
#<bloc_instructions>
(docstring)
help(nom_fonction) # affiche le docstring de la fonction
19
Le bloc d'instructions est obligatoire. S'il ne fait rien, on emploie l'instruction pass.
La documentation est fortement conseillée. Les DocString évoqués précédemment se rattachent à
l'élément qui les précède et, dans le cas d'une fonction, peuvent être réaffichés à l'aide de la fonction
help comme dans l'exemple ci-dessus.
Les paramètres
En python, on dit que les paramètres sont "passés" par affectation :
• Chaque argument de la définition de la fonction correspond, dans l'ordre, à un paramètre de
l'appel.
• La correspondance se fait en place par affectation.
Exemple :
def ma_fonction(x, y, z) :
pass
# Appel de la fonction :
## le passage d'arguments se fait dans l'ordre, par affectation :
ma_fonction(7, 'k', 2.718)
# x = 7, y = 'k', z = 2.718
Dans le cas cité en exemple, notre fonction va calculer le max de trois nombres, aura comme entrées
les trois nombres, que l'on peut nommer comme on veut, et aura pour sortie un nombre, le
maximum du triplet fourni.
Nous obtenons donc :
def cherche_max_triplet(a,b,c):
"""
Fonction qui étant donnés trois nombres a, b, c retourne le maximum
a : float
b : float
c : float
-> float
"""
maxi = a
if b > maxi:
maxi = b
if c > maxi :
maxi = c
else :
if c > maxi :
maxi = c
return maxi
Encore une fois, il faudra bien respecter la syntaxe avec ":" et l'indentation.
Du coup, notre programme devient :
def cherche_max_triplet(a,b,c):
"""
Fonction qui étant donnés trois nombres a, b, c retourne le maximum
a : float
b : float
c : float
-> float
"""
maxi = a
if b > maxi:
20
maxi = b
if c > maxi :
maxi = c
else :
if c > maxi :
maxi = c
return maxi
###########################################################################
#Programme principal
###########################################################################
a, b, c = input('Entrez trois nombres séparés par une virgule :\n')
max1 = cherche_max_triplet(a,b,c)
print max1
a, b, c = input('Entrez à nouveau trois nombres séparés par une virgule :\n')
max2 = cherche_max_triplet(a,b,c)
print max2
a, b, c = input('Entrez enfin trois nombres séparés par une virgule :\n')
max3 = cherche_max_triplet(a,b,c)
print max3
maximum = cherche_max_triplet(max1,max2,max3)
print maximum
La fonction est définie avant son appel.
Portée des variables
Les variables définies dans la fonction cherche_max_triplet ci-dessus sont locales, c'est-à-dire
qu'elles n'existent pas en dehors de cette fonction et ne risquent pas de modifier les autres variables
contenues dans le programme.
Voici un autre exemple pour illustrer cela :
r = 5
def test():
r = 18
return r
print "Dans la fonction, r = ", test()
print "A l'extérieur, r = ", r
Voici le résultat du programme :
Dans la fonction, r =
A l'extérieur, r = 5
18
À l'inverse, si l'on définit la variable r comme globale dans la fonction ( à l'aide du mot clé global ) :
r = 5
def test():
global r
r = 18
return r
print "Dans la fonction, r = ", test()
print "A l'extérieur, r = ", r
21
Alors on obtient :
Dans la fonction, r = 18
A l'extérieur, r = 18
Valeurs par défaut
Il est possible également de préciser des valeurs par défaut aux paramètres d'une fonction. Cela
permet notamment d'éviter à l'utilisateur de préciser systématiquement les valeurs de paramètres
qui varient rarement.
Exemple :
def initPort(speed=9600, parity="paire", data=8, stops=1):
print "Initialisation a", speed, "bits/s"
print "parite :", parity
print data, "bits de donnees"
print stops, "bits d'arrêt"
# Appels possibles :
initPort()
# prise en compte de toutes les valeurs par défaut
initPort(parity="nulle")
# les paramètres nommés sont modifiés
initPort(2400, "paire", 7, 2)
# tous les paramètres sont fournis
#  il n'est donc pas nécessaire de les nommer
Exercice 12 :
On donne le fichier de script erreur.py. Vous pouvez le récupérer sur le site du cours. Chacune des
fonctions qui s'y trouvent contient une unique erreur.
Modifiez chacune des fonctions, l'une après l'autre afin que le script fonctionne de manière
satisfaisante c'est-à-dire qu'il affiche :
Somme1 : 25
Somme2 : 29
Somme3 : 31
Veillez en faisant cela à respecter les DocString des fonctions qui précisent les entrées (paramètres
nommés) et sorties attendues (précédées du symbole ->).
3.6 Importer un module de fonctions
Définition
Un module est un fichier de script indépendant contenant notamment la définition d'un ensemble de
fonctions (bibliothèque de fonctionnalités) que l'on veut pouvoir réutiliser dans diverses
circonstances, divers programmes.
Il permet ainsi d'éviter les redondances entre différents programmes. L'usage de modules permet
également de rattacher une documentation spécifique à un ensemble de fonctionnalités et les tests
22
nécessaires à la validation de son bon fonctionnement. Ceci permettant donc à la fois un gain de
temps et de sécurité.
Il existe un grand nombre de modules pré-programmés qui sont fournis d'office avec Python.
Le module math, par exemple, contient les définitions de nombreuses fonctions mathématiques
telles que sinus, cosinus, tangente, racine carrée, etc. Pour pouvoir utiliser ces fonctions, il vous suffit
d'incorporer la ligne suivante au début de votre script :
from math import *
Cette ligne indique à Python qu'il lui faut inclure dans le programme courant toutes (symbole *) les
fonctions du module math.
Si l'on n'utilise que quelques fonctions d'un module, il est préférable de lister celles-ci après le mot
clé import comme dans l'exemple ci-dessous avant d'alléger le traitement à réaliser.
En effet, un import peut être vu comme la réécriture au sein du script considéré des éléments
importés.
Exemple :
from math import pi, sqrt, sin
nombre = 121
angle = pi/6 # soit 30°
print 'racine carrée de', nombre, '=', sqrt(nombre)
print 'sinus de', angle, 'radians', '=', sin(angle)
L'exécution de ce script provoque l'affichage suivant :
racine carrée de 121 = 11.0
sinus de 0.523598775598 radians = 0.5
Pour utiliser un module dans un autre programme il est également possible d'utiliser l'instruction
suivante :
import <nom du module> [as nom_choisi]
Dans ce cas la totalité des fonctionnalités du module seront importées et pourront être utilisées. Lors
de l'appel de l'une d'entre elles il sera en revanche nécessaire de faire précéder le nom de la fonction
par le nom du module, les deux étant séparés par un '.' qui marque l'"appartenance" de la fonction
au module en question.
Exemple :
import math
print 'La racine carrée de 100 est ', math.sqrt(100)
L'exécution de ce script provoque l'affichage suivant :
La racine carrée de 100 est 10.0
Ce mode d'import peut être coûteux notamment si le module est conséquent et que l'on n'utilise
qu'une petite partie de ses fonctionnalités. Dans un tel cas, comme indiqué ci-dessus, il faudra lui
préférer la syntaxe :
from <nom du module> import obj1, obj2...
qui n'importe que les fonctions obj1, obj2... du module concerné.
23
Il en est de même avec vos propres modules à la nuance près que si vous souhaitez importer un de
vos modules se trouvant dans un répertoire différent de celui où est stocké le script dans lequel vous
voulez l'insérer il faudra préciser son chemin. Nous aurons l'occasion de tester cela par la suite.
Quelques modules utiles

math : comme décrit plus haut, ce module permet d'utiliser les fonctions et constantes
classiques en math : les fonctions trigonométriques ( cos(), sin(), tan(), etc...), fonction racine
( sqrt() ), les nombres pi et e, les logarithmes et exponentielles ( log(), log10(), exp() ), partie
entière et partie fractionnaire ( modf() ), valeur absolue( abs() et fabs() ), etc....

random : offre tout un panel de fonctions pour générer des nombres de manière aléatoire.
Par exemple, la fonction randint(a,b) qui rend un nombre entier compris entre a et b :
randint(1,10) #fournit une valeur entre 1 et 10 par exemple 5
ou random() qui renvoie un nombre réel compris entre 0 et 1 :
random() #vaut par exemple 0.39041964805607265


time et datetime : modules permettant la gestion du temps et des dates, avec des
conversions, calculs, etc...
re : pour le traitement des expressions régulières (un motif dans une chaîne de caractères) (
par exemple pour vérifier dans un formulaire si une adresse email a été rentrée
correctement ).
Le site pypi.python.org/pypi recense plus de 4500 packages !
Exercice 13 :
1.
Écrire un programme nommé age.py qui, en utilisant le module random, permet de tirer
aléatoirement un nombre entre 1 et 100, de le stocker dans une variable nommée age et de
l'afficher à l'écran.
2. Compléter votre programme en créant une fonction nommée tester_age qui étant donné une
valeur d'âge affichera "Vous êtes un enfant" si l'âge est inférieur à 10.
3. Compléter votre programme afin d'utiliser votre fonction tester_age pour un âge aléatoire.
4. Compléter enfin votre fonction pour qu'elle affiche :
 "Vous êtes un enfant" si l'âge est inférieur à 10,
 "Vous êtes un adolescent" si l'âge est compris entre 10 et 17,
 "Vous êtes un adulte" si l'âge est compris entre 18 et 49,
 "Vous êtes un vétéran" si l'âge est supérieur ou égal à 50.
24
3.7 Structure générale d'un script Python
Pour terminer cette partie et compte tenu des différentes notions présentées, voici un petit
graphique présentant la structure générale d'un script Python. Toutes les instructions qui s'y
trouvent n'ont pas encore été présentées, mais ce qui nous intéresse ici c'est uniquement la
structure du fichier que l'on retrouvera systématiquement.
En résumé, un script fera apparaître dans cet ordre :




l'encodage utilisé
la liste des modules importés
la liste des fonctions définies
un ensemble d'instructions qui constitue le "programme principal" c'est-à-dire en quelque
sorte le chef d'orchestre, le pilote qui va nous guider à la solution recherchée. Cet ensemble
d'instructions est la traduction dans le langage choisi de l'algorithme que l'on a conçu pour
répondre à un problème donné.
25
Entête d'un module
Afin d'assurer une bonne réutilisabilité d'un module, sa documentation est importante et est de
manière conventionnelle analogue à ce qui suit :
#!/bin/env python
# -*- coding: utf-8 -*"""Jeu de carte."""
# Assure le fonctionnement du script sur tous les systèmes.
# définit l'encodage
# nécessaire dès que l'on utilise des chaînes de caractères
# le docstring du script
# fichier : mon_fichier.py
# auteur(s) : Dupond et Durand
# nom du script
# noms des auteurs
26
Séance 2
4 Boucles et séquences
4.1 Répétitions en boucle - l'instruction while
L'une des choses que les machines font le mieux est la répétition sans erreur de tâches identiques. Il
existe bien des méthodes pour programmer ces tâches répétitives. Nous allons commencer par l'une
des plus fondamentales : la boucle construite à partir de l'instruction while.
Exercice 14 :
Dans un script nommé premiere_boucle.py veuillez saisir les instructions ci-dessous :
a = 0
while (a < 7) :
a = a + 1
print a
# (n'oubliez pas le double point !)
# (n'oubliez pas l'indentation !)
Exécutez votre script. Que se passe-t-il ?
La syntaxe est donc :
while (condition):
instruction 1
instruction 2
...
instruction n
# retour à la ligne pour la suite du programme
Tant que la condition est vérifiée (de valeur égale à True), les instructions de 1 à n seront effectuées.
Il faut comme toujours en Python bien faire attention à respecter la même indentation pour chaque
instruction dans la boucle. Le retour à la ligne signifie la fin des instructions à répéter dans la boucle
while.
Ainsi l'écriture suivante :
while (condition):
instruction 1
instruction 2
...
instruction n-1
instruction n
signifie que seules les instructions 1 à n-1 seront effectuées si la condition de la boucle est vrai.
Lorsque la condition sera fausse alors le programme se poursuivra en reprenant à l'instruction n.
Avant d'écrire ce genre de boucles, assurez-vous qu'elle n'est pas infinie ! Autrement dit, assurezvous que la condition d'entrée dans la boucle sera forcément fausse à un moment donné. Ce dont
27
elle dépend devra donc évoluer au sein de la boucle afin que si on y est entré on puisse en ressortir
tôt ou tard.
Par exemple, le code suivant lancera un programme qui ne s'arrêtera jamais :
n = 5
while (n > 0):
print n
Le problème est que la valeur de n ne change pas, et donc la condition n > 0 est toujours vérifiée, la
boucle ne se finit jamais.
Pour corriger, il faut qu'à un moment donné n devienne négatif ou nul, voici un exemple de solution :
n = 5
while (n > 0):
print n
n = n - 1
La valeur de n baisse de un à chaque fois que la boucle s'exécute, et atteindra à un moment ou à un
autre 0.
Exercice 15 :
Combien de fois va-t-on avoir un résultat affiché dans le code ci-dessus ?
Exercice 16 : Construction d'une suite mathématique
Analysez le programme ci-dessous, décrivez le mieux possible le rôle de chacune des instructions et
donnez son résultat.
a = 1
b = 1
c = 1
while c < 11 :
print b,
temp = b
b = a + b
a = temp
c = c+1
Vérifiez votre réponse en transcrivant ces instructions dans un script que vous nommerez fibo.py.
28
Exercice 17 :
Écrire un programme qui affiche les 20 premiers termes de la table de multiplication par 7. Vous
nommerez ce programme multi_7.py.
Exercice 18 : Devine un nombre !
Écrire un programme devine.py utilisant le module random pour implémenter le petit jeu devine un
nombre. L'ordinateur « choisit » un nombre et propose à l'utilisateur de le deviner. L'ordinateur
guide alors l'utilisateur en lui indiquant si le nombre qu'il propose est plus grand ou plus petit que le
nombre attendu.
Exercice 19 :
Écrire un programme simule_de.py utilisant le module random qui simule le lancé d'un dé à 6 faces,
autant de fois que l'utilisateur le désire (celui-ci peut très bien choisir de lancer un million de fois le
dé). L'utilisateur choisit le nombre de lancés ainsi qu'une valeur d'intérêt valide, et doit voir
apparaitre le nombre de lancés positifs c'est-à-dire égaux à la valeur d'intérêt choisie par l'utilisateur.
4.2 Les séquences
Définition
Une séquence est un conteneur ordonné d‘éléments indicés par des entiers. Python dispose de trois
types prédéfinis de séquences :



les chaînes ;
les listes ;
les tuples.
Fonctions et méthodes
On peut agir sur les séquences en utilisant des fonctions (notation procédurale) qui vont être
communes aux différents types de séquences et des méthodes (notation objet) qui vont être
spécifiques à un type de séquence en particulier.
Pour appliquer une fonction on utilise directement l'opérateur (). Par exemple, si l'on veut avoir
accès à la longueur d'une séquence, il s'agit d'une fonction nommée len que l'on utilise
classiquement comme suit :
sequence = "abc"
longueur = len(sequence)
print longueur
#affichera 3 dans ce cas
On applique en revanche une méthode à une séquence (de manière plus générale à un objet) en
utilisant la notation pointée. Par exemple, la méthode upper s'applique uniquement aux chaînes de
caractères (nous y reviendrons pas la suite) et réalise une mise en majuscule.
29
Elle s'utilise comme suit :
sequence = "abracadabra"
seq2 = sequence.upper()
print seq2
#affichera 'ABRACADABRA'
Parcourir une séquence :
Outre la boucle while vue précédemment, il existe en Python un autre mécanisme de boucle
spécialement conçu pour parcourir des séquences lorsque l'on n'a pas besoin de savoir où on en est
dans notre parcours mais uniquement d'accéder aux différentes valeurs de la séquence les unes
après les autres. L'instruction à utiliser dans ce cas est for.
Exemples :
for lettre in "ciao":
print lettre,
for x in [2, 'a', 3.14]:
print x,
for i in range(5):
print i,
#la virgule permet d'obtenir les différents éléments
#sur une même ligne
# affiche c i a o
#affiche 2 a 3.14
#affiche 0 1 2 3 4
Syntaxe générique :
for element_courant in ma_sequence :
<bloc d’instructions>
element_courant est une variable que l'on choisit pour stocker à chaque "tour" de boucle l'élément
que l'on considère dans la séquence ma_séquence.
Ainsi, à la ième itération de la boucle, est stocké dans la variable element_courant le i ème élément de la
séquence parcourue.
Après ces quelques généralités, nous allons voir plus en détails les deux principaux types de
séquences en Python : les chaînes de caractères et les listes.
4.3 Utilisation des chaînes de caractères
Une chaîne de caractères est une séquence de lettres et s'écrit en plaçant cette chaîne soit entre
deux guillemets (ex. "exemple") soit entre deux simples quotes (ex. 'exemple') soit, plus rarement,
entre triples guillemets lorsque l’on veut préserver la mise en page (sauts de lignes).
Les guillemets permettent d'inclure des apostrophes :
c1 = "L'eau vive"
Les apostrophes permettent d'inclure des guillemets :
30
c2 = ' est "froide" !'
Les triples guillemets ou triples apostrophes conservent la mise en page (lignes multiples) :
c3 = """Usage :
-h : help
-q : quit"""
Exercice 20 :
Ouvrez le script premieres_chaines.py. Analysez son contenu et le résultat produit à son exécution.
Qu'en déduisez-vous sur les effets des opérateurs utilisés ?
Les chaînes de caractères : opérations en résumé
Dans vos tests précédents vous avez dû constater que les opérateurs + et * ont un sens particulier
pour les chaînes de caractères.
Concaténation :
s1 = "abc"
s2 = "defg"
s3 = s1 + s2
#s3 vaut donc 'abcdefg'
Répétition :
s4 = "Fi! "
s5 = s4 * 3
#s5 vaut donc 'Fi! Fi! Fi!'
Accès aux éléments d’une chaîne de caractères
L’opérateur [ ] permet d’extraire un (ou plusieurs) caractère(s) d’une chaîne. Les caractères d’une
chaîne de caractères sont numérotés de manière croissante de gauche à droite à partir de 0 et de
manière décroissante de droite à gauche à partir de -1.
0 1 2 3 4 5 6
b o n j
o u r
-7 -6 -5 -4 -3 -2 -1
Soit chaine une variable de type chaîne de caractères.
– chaine[i]
renvoie le caractère en position (ou indice) i dans chaine ;
– chaine[i:j]
renvoie la sous-chaîne commençant à l’indice i et se terminant à l’indice j-1 ;
– chaine[i:]
renvoie le suffixe débutant en position (ou indice) i dans chaine ;
– chaine[:j]
renvoie le préfixe se terminant en position (ou indice) j-1 dans chaine.
31
Quelques exemples particuliers pour chaine="bonjour" :
– chaine[-1]
vaut r ;
– chaine[0:3]
(ou chaine[ :3]) vaut bon ;
– chaine[4:]
vaut our ;
– chaine[0:-2]
(ou chaine[ :-2]) vaut bonjo ;
– chaine[3:6]
vaut jou ;
– chaine[-5:-2]
vaut njo.
Attention !
Les chaînes de caractères ne sont pas modifiables en Python, c'est-à-dire que l'on ne peut pas
affecter directement uniquement un caractère de la chaîne.
Autrement dit, la syntaxe chaine[3] = 2 n’est pas correcte.
Fonctions utiles
La fonction len(chaine) renvoie la longueur de chaine. Par exemple, len("bonjour") renvoie 7.
Il existe également des méthodes permettant d’effectuer facilement des opérations sur les chaînes
de caractères, parmi celles-ci (liste non exhaustive) :
•
find() : donne la position d'une sous-chaîne dans la chaîne (la première position vaut 0) :
'abracadabra'.find('bra')
•
# 1
count() : donne le nombre de sous-chaînes dans la chaîne :
'abracadabra'.count('bra')
•
# 2
lower() : convertit en minuscules :
'PETIT'.lower()
•
#'petit'
upper() : convertit en majuscules :
'grand'.upper()
•
#'GRAND'
capitalize() : convertit la première lettre en majuscule :
'michelle'.capitalize()
•
#'Michelle'
title() : la première lettre de tous les mots en majuscule :
'un beau titre !'.title()
•
#'Un Beau Titre !'
swapcase() : intervertit les casses :
'bOB'.swapcase()
•
"
strip() : supprime les espaces en début et fin de chaîne :
Trop d'espaces
•
#'Bob'
".strip()
#"Trop d'espaces"
replace() : remplace une sous-chaîne par une autre :
'abracadabra'.replace('a', 'o')
#'obrocodobro'
32
Exercice 21 :
Quels sont les valeurs et types des expressions Python suivantes :
Valeur
Type
len("polololom")
"bonhomme"[0 :3] + ’assoir’[2 :]
123.replace(1,6)
"o" in ’coin’.replace(’o’, ’a’)
679[2] + 3
len("123") + 123
5 * "exemple".find(’em’)
"123".replace("1", "6")
x='marche'[:3]+'bandit'[3:5]+"_"+str(5**2)+' '+"octobre"
Parcours d’une chaîne de caractères
Une chaîne de caractères en Python étant une séquence, nous avons donc à disposition en plus de la
boucle while la boucle for présentée précédemment.
Exemples :
for lettre in "bonjour":
print lettre,
# b o n j o u r
Exercice 22 :
Dans un script chaines.py créez, les unes après les autres, les fonctions détaillées ci-dessous et le
programme principal qui permet de les tester. Pour chaque fonction vous veillerez à la documenter
soigneusement et notamment à bien préciser ses entrées et ses sorties comme suit :
def ma_fonction (param1, param2, ...) :
"""
Rôle de la fonction ma_fonction
param1 : type
param2 : type
...
sortie : type
"""
...
return sortie
33
1. Écrire une fonction detail_chaine récupérant un texte ou une phrase de l'utilisateur, et qui
affiche sur plusieurs lignes :
 le texte ou la phrase donnés,
 le nombre de caractères contenus,
 le premier et le dernier caractères, séparés par trois petits points ...
2. Écrire une fonction affiche_colonne qui affiche les lettres d'une chaîne de caractères donnée
par l'utilisateur ( une par ligne ).
3. Écrire une fonction insere_star qui pour une chaîne de caractères donnée en paramètre
retourne une nouvelle chaîne construite sur la base de la première en insérant une
astérisque entre chacune de ses lettres (ex: gaston --> g*a*s*t*o*n ).
4. Écrire une fonction teste_lettre qui teste si une phrase contient une lettre, les deux éléments
étant fournis comme paramètres et retourne le nombre de fois où cette lettre apparait dans
le phrase.
5. Écrire une fonction palindrome qui prend en entrée une chaîne de caractères et retourne
True si c'est un palindrome (c'est à dire une chaîne de caractères s'écrivant de la même façon
de gauche à droite et de droite à gauche comme : non, radar...) et False dans le cas contraire.
6. Écrire une fonction ligne_star qui prend en entrée un entier n et retourne une chaîne de
caractères composée de n fois le symbole *.
Par exemple pour n = 5, la fonction devra retourner la chaîne : *****
7. Écrire une fonction carre_star qui prend en entrée un entier n et retourne une chaîne de
caractères semblable à un carré d'étoiles de côté n. Pensez pour cela à utiliser la fonction
ligne_star.
Par exemple pour n = 3, la fonction devra retourner la chaîne :
***
***
***
8. Écrire enfin une fonction triangle_star qui prend en entrée un entier n et retourne une
chaîne de caractères semblable à un triangle rectangle d'étoiles.
Par exemple pour n = 6, la fonction devra retourner :
******
*****
****
***
**
*
34
Séance 3
4.4 Les listes
Une liste en Python est une collection hétérogène, ordonnée et modifiable d’éléments séparés par
des virgules, et entourée de crochets.
Ce sont des objets qui peuvent en contenir d'autres. C'est donc une séquence, comme une chaîne de
caractères, mais qui, au lieu de contenir des caractères, contient n'importe quel objet. Au sein d’une
même liste on peut trouver des objets de types différents (entiers, flottants, chaînes de caractères,
listes, ...).
Les listes en Python s'initialisent très simplement grâce à l’opérateur [ ].
Quelques exemples de listes :
ma_liste = []
print ma_liste
# on crée une liste vide
# affichera []
ma_liste = [1, 2, 3, 4, 5]
print ma_liste
# une liste avec cinq objets
# [1, 2, 3, 4, 5]
ma_liste = [1, 3.5, "une chaine", []]
#4 objets de types différents
Accès aux éléments d’une liste
Les modes d'« accès » présentés pour les chaînes de caractères sont également valables pour les
listes.
couleurs = ['trefle', 'carreau', 'coeur', 'pique']
print couleurs
# affichera ['trefle', 'carreau', 'coeur', 'pique']
print couleurs[1]
# affichera carreau
list1
list2
list3
print
= ['a', 'b']
= [4, 2.718]
= [list1, list2]
list3
machin = [0.0] * 3
# liste de listes
# affichera [['a', 'b'], [4, 2.718]]
# [0.0, 0.0, 0.0]
Il faut y rajouter quelques éléments compte tenu du fait que les listes sont modifiables à l’inverse des
chaînes de caractères.
Modification :
couleurs[1] = 14
print couleurs
# affichera ['trefle', 14, 'coeur', 'pique']
mots = ['jambon', 'sel', 'confiture']
mots [1] = 'piment'
print mots
# affichera ['jambon', 'piment', 'confiture']
Insertions et suppressions :
Dans le membre de gauche d'une affectation, il faut obligatoirement indiquer une tranche pour
exécuter une insertion ou une suppression.
35
Le membre de droite doit lui-même être une liste.
mots = ['jambon', 'sel', 'confiture']
mots[2:2] = ['miel']
# insertion en 3e position
mots[4:4] = ['beurre']
# insertion en 5e position
print mots
# affichera ['jambon','sel','miel','confiture', 'beurre']
mots[2:4] = []
print mots
# effacement par affectation d'une liste vide
# affichera ['jambon', 'sel', 'beurre']
Fonctions utiles

sort() : permet d’ordonner une liste
nombres = [17, 38, 10, 25, 72]
nombres.sort()
# [10, 17, 25, 38, 72]

append() : permet d’ajouter en queue de liste
nombres.append(12)

# [10, 17, 25, 38, 72, 12]
reverse() : permet de renverser une liste
nombres.reverse()

# [12, 72, 38, 25, 17, 10]
index(val) : donne la position de l’élément val
nombres.index(17)

# 4
remove(val) : permet de supprimer l’élément val de la liste
nombres.remove(38)

# [12, 72, 25, 17, 10]
range() : permet de créer des listes d’entiers
range(4)
# [0, 1, 2, 3]
range(4, 8)
# [4, 5, 6, 7]
range(2, 9, 2)
# [2, 4, 6, 8]
chose = range(6)
print 3 in chose
# [0, 1, 2, 3, 4, 5]
# teste l'appartenance donc affichera True
4.5 Conversions liste – chaîne de caractères
Dans certains cas de figure, il peut être intéressant de passer d'une chaîne de caractères à une liste
et vice versa. Pour cela nous disposons des deux méthodes suivantes :
•
split() : scinde une chaîne en une liste de mots suivant un caractère de séparation :
'ab*cd'.split('*')
•
# (on indique le séparateur)
# ['ab', 'cd']
join() : concatène plusieurs chaînes en une seule chaîne suivant un caractère de jonction :
'-'.join(['ci', 'joint'])
# (on indique le caractère de "liaison")
#'ci-joint'
Celles-ci sont propres aux chaînes de caractères.
36
Exercice 23 :
Dans un script listes.py créez, les unes après les autres, les fonctions détaillées ci-dessous et le
programme principal qui permet de les tester. Pour chaque fonction vous veillerez à la documenter
soigneusement et notamment à bien préciser ses entrées et ses sorties comme précédemment pour
les fonctions se rapportant aux chaînes de caractères.
1. Écrire une fonction renverse_sans_bords qui renverse le contenu d'une liste sauf le premier
et le dernier élément et testez-la. Par exemple, la liste [1, 2, 3, 4, 5] deviendra [1, 4, 3, 2, 5].
2. Écrire une fonction permute_demi qui permute la première moitié d'une liste avec l'autre
moitié et testez-la. Par exemple, [1, 2, 3, 4, 5] devient [ 4, 5, 3, 1, 2].
3. Écrire une fonction pairs_impairs qui construit une liste des 100 premiers entiers, puis
l'éclate en deux listes, l'une avec les nombres pairs et l'autre avec les nombres impairs et
retourne la liste de ces listes.
4. Écrire une fonction indice(e,l) qui renvoie l’indice de la première occurrence de l’élément e
dans la liste l (si e est présent dans l) et qui renvoie la longueur de l sinon.
5. Écrire une fonction sousListe(pL, gL) qui renvoie un booléen qui dit si les éléments de pL
apparaissent dans gL, et ce dans le même ordre.
Par exemple, sousListe([2,4,10], [1,2,4,5,6,8,10,12]) renvoie True.
6. Tri
1. Écrire une fonction insere qui prend en argument une liste l supposée triée par ordre
croissant, et un nouvel élément e, et qui renvoie la liste obtenue en insérant l’élément e à la
bonne place pour que le résultat soit encore une liste triée.
2. Écrire une fonction tri qui prend une liste en argument et renvoie la liste triée. On utilisera
le tri par insertion : au début, on crée une nouvelle liste vide, et ensuite, pour chaque
élément e de la liste d’origine, on insère e dans la nouvelle liste comme indiqué dans la
question précédente.
7. Histogramme
Écrire une fonction histo_de utilisant le module random qui simule le lancé d'un dé à 6 faces,
autant de fois que l'utilisateur le désire (celui-ci peut très bien choisir de lancer un million de
fois le dé) et retourne le nombre de résultats pour chacun des 6 chiffres.
8. Compression de données
Une séquence d’ADN peut être très longue et contenir des répétitions. Le but de cet exercice
est d’écrire une fonction qui prend un long brin d’ADN et qui renvoie la même information
sous une forme condensée.
L’idée est de ne pas répéter un nucléotide répété mais de mémoriser dans la liste son
nombre d’occurrences.
On considèrera que le brin d’ADN est passé sous forme d'une chaîne de caractères. Ainsi
comprime('AAAGCTTCCCG' retourne [’A’,3,’G’,’C’,’T’,2,’C’,3,’G’]
1. Ecrivez la fonction comprime
2. Ecrivez la fonction deploie qui fait l’opération inverse.
37
Exercice 24 : Le jeu du pendu
Règles du jeu :
L'ordinateur choisit un mot au hasard dans une liste, un mot de huit lettres maximum. Le joueur
tente de trouver les lettres composant le mot.
À chaque coup, il entre une lettre. Si la lettre est dans le mot, l'ordinateur affiche le mot avec les
lettres déjà trouvées. Celles qui ne le sont pas encore sont remplacées par des étoiles (*).
Le joueur a 8 chances. Au-delà, il a perdu.
Implémentez ce jeu en Python.
38
4.6 Retour sur l'affectation
L'opération d'affectation en Python réalise plusieurs actions.
Exemples :
i = 1
msg = "Quoi de neuf ?"
e = 2.718
Quel que soit le type de l'élément concerné, lorsqu'une affectation est réalisée comme dans les
exemples ci-dessus, les opérations suivantes sont réalisées :




créer et mémoriser un nom de variable (membre de gauche) dans l'espace de noms courant
(c'est en fait une adresse) ;
lui attribuer dynamiquement un type bien déterminé ;
créer et mémoriser une valeur (membre de droite) ;
établir un lien entre le nom de la variable et l'adresse de la valeur correspondante.
Le problème des références
Considérons l'exemple ci-dessous.
Exemple :
fable = ['Je', 'plie', 'mais', 'ne', 'romps', 'point']
phrase = fable
fable[4] = 'casse'
print phrase
#affichera ['Je', 'plie', 'mais', 'ne', 'casse', 'point']
Nous créons ici une liste et nous établissons un lien entre cette liste et une variable nommée fable.
Puis nous affectons une nouvelle variable phrase à la valeur référencée par fable. Autrement dit nous
faisons le lien entre phrase et notre liste de départ. Nous avons donc deux variables qui nous
permettent d'y accéder. En utilisant notre premier moyen d'accès, nous modifions ensuite le 5ième
valeur de notre liste, toujours la même et unique liste. Enfin lorsque nous regardons, par notre
deuxième accès possible, le contenu de notre liste nous observons la modification réalisée.
Le schéma ci-dessous résume ce mécanisme.
39
Le mécanisme d'affection n'est donc pas un mécanisme de copie de valeur mais de référencement
d'adresse un peu comme si vous aviez fait un double de la clef de votre porte d'entrée. En définitive,
vous disposeriez de deux clefs mais toujours d'une unique porte.
En conséquence, si l'on désire réaliser une vraie copie d'un objet, on doit utiliser le module copy :
import copy as cpy
a = [1, 2, 3]
b = a
# une référence
b.append(4)
print a
# affichera [1, 2, 3, 4]
c = cpy.copy(a)
c.append(5)
print c
# une copie de "surface"
print a
# affichera [1, 2, 3, 4]
# affichera [1, 2, 3, 4, 5]
Pour une copie en profondeur, c'est-à-dire lorsqu'un objet modifiable contient des objets modifiables
il faudra avoir recours à la fonction copy.deepcopy().
40
Séance 4
5 Programmation de graphiques - séquences
Bien que de nombreux logiciels de visualisation de données soient disponibles, souvent les besoins
des utilisateurs vis-à-vis de la visualisation de leurs données sont spécifiques et savoir programmer
des graphiques personnalisés s’avère indispensable. Pour cela le langage Python est complété par
une librairie très fournie : la librairie matplotlib. Pour ce TD nous utiliserons également la
bibliothèque random.
5.1 Présentation des bibliothèques
Rappels : Une bibliothèque est un fichier python (script) qui contient des instructions définissant un
certain nombre de fonctions. On l’importe à l’aide des commandes :
import (nom de la bibliothèque)
ou :
import (nom de la bibliothèque) as (abréviation)
Exemple :
import random
import random as rd
Dans le premier cas on appellera la fonction gauss avec la syntaxe random.gauss, dans le second
avec rd.gauss.
5.1.1
La bibliothèque random
La bibliothèque random donne des outils pour générer des nombres pseudo-aléatoires.
•
•
random.random() : retourne un flottant pseudo-aléatoire de l’intervalle [0.0, 1.0[.
random.gauss(mu,sigma) : retourne un flottant pseudo-aléatoire selon la loi gaussienne
de moyenne mu et d'écart-type sigma.
•
random.randrange(start, stop[, step]) : retourne un élément au hasard de la liste
range(start,stop, step).
•
random.randint(a,b) : retourne un entier de [a,b].
Une liste exhaustive des fonctions se trouve sur http://docs.python.org/3/library/random.html
avec des exemples.
41
Exercice 25 :
Écrire dans un script genere.py une fonction liste_alea qui étant donnés trois entiers nb, mini et maxi
retourne une liste de nb nombres flottants aléatoires compris entre mini et maxi au sens large.
5.1.2
La bibliothèque matplotlib
La bibliothèque matplotlib donne des outils pour faire des graphiques en 2D et en 3D. On peut faire
aussi bien des graphes de fonctions, des histogrammes que des opérations assez poussées (de
nombreux exemples sur http://matplotlib.org/gallery.html).
C’est une bibliothèque robuste et efficace utilisée par de nombreuses autres bibliothèques.
La bibliothèque est documentée à l'adresse suivante : http://matplotlib.org/api/pyplot_api.html
Matplotlib permet de réaliser des nuages de points notamment en deux dimensions et de les
paramétrer suivant différents critères. Il est notamment possible d'utiliser des symboles divers et des
couleurs afin par exemple de distinguer des groupes au sein des éléments représentés, de
dimensionner spécifiquement chaque point pour prendre en compte un troisième descripteur, de
réaliser des légendes pour rendre le graphique explicite, etc.
Figure 5 : Exemple de nuage de points obtenu avec Matplotlib
42
Cette librairie permet également de réaliser des courbes avec des styles de traits différents, des
barres d’erreurs, du remplissage, plusieurs tracés, des légendes, etc.
Figure 6 : Exemple de courbe avec des barres d'erreurs et
une légende
Figure 7 : Exemple de courbe avec du remplissage
Certaines fonctions fournies permettent la création de diagrammes en bâtons et d'histogrammes
verticaux ou horizontaux, éventuellement pour plusieurs groupes, avec ou sans barres d’erreurs,
avec des légendes, etc.
Figure 8 : Exemples de diagrammes en bâtons et d'histogrammes
Souvent, lorsque l'on souhaite produire ses propres graphiques, on va vouloir combiner différents
types :



Des courbes avec des nuages
Des nuages avec des histogrammes
etc.
43
Figure 9 : Exemples de graphiques combinés
Il nous faudra alors gérer l’ordre d’affichage afin d'assurer un rendu satisfaisant.
Figure 10 : Courbe et points mal superposés
Figure 11 : Courbes et points superposés de manière
satisfaisante
Il peut être intéressant dans certains cas de proposer plusieurs graphiques sur une même figure par
exemple pour pouvoir visualiser simultanément plusieurs projections en deux dimensions d'un nuage
de points en dimension plus grande.
44
Les Nuages de points
Pour réaliser des nuages de points avec Matplotlib il faut avoir recours à la fonction scatter qui
nécessite au minimum deux arguments :


Une liste des valeurs en X (axe horizontal)
Une liste des valeurs en Y (axe vertical)
Chaque couple (x,y) représentant la position d'un point à matérialiser sur le graphique, les listes X et
Y doivent être de même taille.
Exemple :
L'instruction scatter ([0,1,2,3,4,5],[0,1,2,3,4,5]) à incorporer dans un script faisant
référence à la bibliothèque Matplotlib correspond au graphique ci-dessous :
Un exemple de script … minimaliste :
# Il nous faut importer la librairie
from pylab import *
# Récupérer des données sous forme de listes
x = rand(100) # génère une liste aléatoire de nombres de [0,1]
y = rand(100) # de longueur 100
# Faire appel à une fonction de dessin
scatter(x,y) # fonction de dessin d’un nuage de points
#enregistrer la figure produite
savefig('premiere_figure.jpg')
#Demander l’affichage
show() # ouvre une fenêtre contenant la figure
# bloque l’exécution
45
Figure 12 : Graphique obtenu par exécution du script ci-dessus
Coloration
Par défaut la fonction scatter représente les points par des disques bleus. Le paramètre nommé c
permet de paramétrer la couleur. Lorsque l'on donne une unique valeur pour ce paramètre tous les
points seront de même couleur.
Par exemple : scatter(x,y, c='r') permet d'afficher en rouge les points dont les coordonnées sont
contenues dans x et y.
Si une liste de valeurs (de même longueur que x et y) est associée au paramètre c alors une couleur
est attribuée dans l’ordre de la liste à chaque point dessiné
Exemple :
from pylab import *
N = 100
x = rand(N)
y = rand(N)
color = ['r']*(N/2) + ['g']*(N/2)
scatter(x,y, c=color)
show()
Figure 13 : Graphique produit grâce au script ci-contre
Il existe quelques couleurs par défaut représentées par un caractère comme dans l'exemple cidessus.
46
Tableau 1 : Couleurs par défaut
‘b’ : blue
‘g’ : green
‘r’ : red
‘c’ : cyan
‘m’ : magenta
‘y’ : yellow
‘k’ : black
‘w’ : white
Un niveau de gris peut également être précisé par un flottant de [0,1] entre apostrophes.
Par exemple : c = '0.75'.
Une couleur peut également être codée par un triplet de valeurs de [0,1] entre parenthèses
représentant des quantités de rouge, vert et bleu (représentation R,G,B).
Par exemple c = (0.0,1.0,0.0)
Il existe d'autres formats possibles pour préciser une couleur (voir la page web de la bibliothèque au
besoin).
Les symboles
Le paramètre nommé marker permet de paramétrer le symbole utilisé pour matérialiser les points.
scatter(x,y, marker = '+')
Figure 14 : Nuage de points représentés par le symbole '+'
Un seul symbole peut être considéré par appel de la fonction scatter. Si dans un graphique nous
souhaitons faire apparaître des points avec des symboles distincts il faudra donc autant d'appels à la
fonction scatter que de symboles différents désirés.
scatter(x[:(N/2)],y[:(N/2)], marker = '+')
scatter(x[(N/2):],y[(N/2):], marker = '^')
Figure 15 : Nuages de points avec deux symboles distincts
47
Comme pour les couleurs, certains symboles sont prédéfinis :
'+'
plus
'1'
tri_down
'_'
Hline
'2'
tri_up
'|'
vline
'3'
tri_left
'x'
x
'4'
tri_right
'v'
triangle_down
'D'
diamond
'<'
triangle_left
'h'
hexagon
'>'
triangle_right
'p'
pentagon
'^'
triangle_up
's'
square
'8'
octagon
'*'
star
'o'
circle
'd'
thin_diamond
Mais il est également possible de définir ses propres polygones (cf. site web de Matplotlib).
Taille des symboles
Le paramètre nommé s permet de paramétrer la taille des symboles. Comme pour la couleur, si une
seule valeur est fournie les points seront tous de même taille.
scatter(x,y, s = 200)
Si en revanche, une liste (de bonne longueur) de valeurs est fournie alors elle détermine position par
position la taille de chacun des points à représenter.
N = 100
x = rand(N)
y = rand(N)
sizes = [20]*(N/2) + [200]*(N/2)
scatter(x,y, s=sizes)
48
Exemple de script combinant les différents effets listés ci-dessus :
#!/usr/bin/env python
from pylab import *
N = 100
x = rand(N)
y = rand(N)
color = ['b']*(N/2) + ['r']*(N/2)
sizes = [40]*(N/4) + [400]*(N/4)+[40]*(N/4) + [400]*(N/4)
scatter(x[:(N/2)],y[:(N/2)], c = color[:(N/2)], marker = '+', s = sizes[:(N/2)] )
scatter(x[(N/2):],y[(N/2):], c = color[(N/2):], marker = '_', s = sizes[(N/2):] )
savefig('premiere_figure.jpg')
show()
Figure 16 : Figure obtenue par exécution du script ci-dessus
Exercice 26 :
Dans un script premiers_nuages.py et en utilisant la fonction développée à l'Exercice 25, écrire une
fonction nuage_alea permettant d'afficher un nuage de points aléatoires. Votre fonction aura
comme paramètres le nombre de points à considérer, l'abscisse minimale, l'abscisse maximale,
l'ordonnée minimale et l'ordonnée maximale autorisées.
Exercice 27 :
Dans le script premiers_nuages.py, écrire une fonction affiche_seuil qui construit un nuage aléatoire
en considérant les bornes x_min, x_max, y_min, y_max en abscisses et en ordonnées et qui étant
donné un seuil s_xy affiche tous les points d'abscisses ou d'ordonnée inférieure à s_xy en bleu et les
autres points en rouge.
Exercice 28 :
On considère 3 points aléatoires particuliers auxquels on associe des couleurs distinctes. On
considère par ailleurs nb points aléatoires (on considère toujours des valeurs extrêmes x_min,
x_max, y_min, y_max). Dans le script premiers_nuages.py, écrire une fonction affiche_groupes
permettant de générer ces ensembles de points et de produire un graphique où les 3 points
d'intérêts sont matérialisés par des marqueurs spécifiques et les autres points portent la couleur du
point d'intérêt qui lui est le plus proche au sens de la distance euclidienne.
49
Les figures multiples
Sur une même figure on peut faire apparaître plusieurs graphiques grâce à la fonction subplot .
Exemple d'usage :
from numpy import sqrt
from numpy.random import rand
from pylab import *
x = rand(10)
y = rand(10)
z = sqrt(x**2 + y**2)
subplot(321)
scatter(x,y,s=80, c=z, marker=">")
subplot(322)
scatter(x,y,s=80, c=z, marker='1')
subplot(323)
scatter(x,y,s=80, c=z, marker='s')
#…
show()
Le script ci-dessus contient les instructions nécessaires à la réalisation des trois premiers graphiques
de la figure ci-dessus. Il est contenu dans le fichier subplot.py.
Exercice 29 :
Compléter ce script afin d'obtenir la figure dans sa totalité.
À quoi correspondent les valeurs du paramètre de la fonction subplot ?
50
Les courbes
Lorsque l'on souhaite tracer des courbes avec Matplotlib, nous avons recours à la fonction plot qui
nécessite au minimum un argument correspondant à la liste des valeurs en Y. Sera alors associée
comme valeur pour l'axe X à chaque valeur de la liste son indice dans la liste.
#!/usr/bin/env python
from pylab import *
N = 100
y = rand(N)
plot(y)
savefig('premiere_courbe.jpg')
show()
Lorsque l'on a des valeurs spécifiques à préciser par l'axe X, nous donnerons comme pour la fonction
scatter deux listes de même longueur à la fonction plot :
•
•
Une liste des valeurs en X
Une liste des valeurs en Y associées
#!/usr/bin/env python
from pylab import *
from numpy import arange
from math import sin
x = arange(0,10,0.01)
y = []
for val in x :
y.append(sin(val))
plot(x,y)
savefig('deuxieme_courbe.jpg')
show()
Couleur du trait
La couleur du trait d'une courbe est déterminée par le paramètre c dont l'usage est analogue aux
nuages de points en fournissant une valeur ou une liste de valeurs.
Style du trait
Le style du trait (plein, pointillé, etc.) est géré par le paramètre linestyle qui admet les valeurs
suivantes :
'-'
Ligne continue
'--'
Ligne tiré
51
'-.'
Ligne mixte
':'
Ligne pointillée
Epaisseur du trait
L'épaisseur du trait est commandée par le paramètre nommé linewidth.
plot(x,y1,linewidth=2, linestyle = '--', c='k')
plot(x,y2,linewidth=2, linestyle = '-.', c='r')
plot(x,y3,linewidth=2, linestyle = ':', c='b')
Marquer les points
Il est également possible de matérialiser par un symbole la position des points fournis pour générer
la courbe grâce au paramètre marker (analogue au nuage de points). La taille du symbole pourra
alors être gérée par le paramètre makersize, tandis que sa couleur sera déterminée par la valeur du
paramètre markerfacecolor.
#!/usr/bin/env python
from pylab import *
from numpy import arange
from math import sin
x = arange(0,10,0.2)
y = []
for val in x :
y.append(sin(val))
plot(x, y, c = 'k', marker = 'o', markersize = 15, markerfacecolor = 'g')
show()
Figure 17 : Courbe dont les points fournis sont matérialisés par des disques vert
52
Superposition de courbes
Lorsque l'on veut tracer plusieurs courbes sur un même graphique il faudra réaliser plusieurs appels
à la fonction plot. L'ordre d’affichage des courbes étant commandé par le paramètre zorder. Les
courbes sont empilées dans l’ordre des zorder croissants comme si il s'agissait d'une valeur sur un
axe pointant vers nous.
from pylab import *
from numpy import arange
from math import sin
x = arange(0,10,0.01)
y1 = []
for val in x :
y1.append(sin(val))
y2 = []
for val in x :
y2.append(sin(val+1.0))
# on top
plot(x,y1,linewidth=10, color='black', zorder = 10)
# bottom
plot(x,y2,linewidth=10, color='red', zorder = 1)
show()
Courbes et erreurs
Lorsque l'on a des données expérimentales à représenter, il est fréquent qu'une mesure soit
entachée d'une erreur potentielle qu'il faut pouvoir retranscrire sur le graphique correspondant afin
que celui-ci soit représentatif. Cela est faisable par appel à la fonction errorbar (x, y, …) qui pourra
prendre en compte des erreurs suivant l'axe horizontal par le paramètre xerr et/ou sur l'axe vertical
par le paramètre yerr.
Exemple :
#!/usr/bin/env python
from pylab import *
from numpy import arange
from math import sin
x = arange(0,10,0.5)
y = [sin(val) for val in x]
plot(x,y)
errorbar(x, y, linestyle = '',
xerr=rand(len(x)), ecolor='r')
errorbar(x, y, linestyle = '',
yerr=rand(len(x)), ecolor='g')
savefig('courbe_erreurs.jpg')
show()
Nous avons deux appels à la fonction errorbar dans l'exemple ci-dessus afin de représenter dans des
couleurs différentes les erreurs en x et en y.
D'autres fonctionnalités (nombreuses) en lien avec le tracé de courbe sont disponibles. Reportezvous à la documentation et aux exemples accessibles sur leur site web pour plus de détails.
53
Exercice 30 :
Une marche aléatoire (en dimension 2) est une suite de points, où chacun est obtenu par un saut
indépendant à partir du point précédent (et rien de plus : le système « perd la mémoire » à chaque
saut).
Dans l’exemple étudié, on autorise les sauts de longueur 1 sur l’axe des x (donc +1 ou −1 sur x) ou
(exclusif) sur l’axe des y (donc +1 ou −1 sur y), de façon équiprobable.
Dans un script marche_alea.py, implémenter les fonctions suivantes :
1. Écrire une fonction positions_alea qui retourne deux listes x_liste et y_liste contenant les
coordonnées (x[i],y[i]) des points d’une marche aléatoire de N pas.
2. Écrire une fonction plot_marche qui prend en entrée deux listes de valeurs et affiche la
courbe correspondante.
3. Écrire une fonction compte_position qui, étant données x_liste et y_liste, détermine pour
chaque position visitée le nombre de fois où elle l'a été. Vous construirez pour cela une liste
qui dans chaque case contient une liste de trois éléments : position en x, position en y et
nombre d'occurrence. Votre fonction retournera cette liste de listes.
4. Écrire une fonction affiche_marche_scatter qui permet d'afficher chaque position visitée lors
de la marche avec un code couleur correspondant au nombre de fois où chacune d'entre
elles a été occupée. Vous utiliserez pour cela la fonction de la question précédente.
Les diagrammes en bâtons
Dès que l'on souhaite représenter des quantités par catégories (nombre d'hommes, nombre de
femmes dans une entreprise par exemple) les diagrammes en bâtons offrent une bonne solution.
Dans la bibliothèque Matplotlib la fonction bar va nous permettre de réaliser de tels graphiques.
Voici un petit exemple d'usage :
#!/usr/bin/env python
from pylab import *
N = 5
menMeans = (20, 35, 30, 35, 27)
menStd =
(2, 3, 4, 1, 2)
ind = range(N) # the x locations for the groups
width = 0.35
# the width of the bars
bar(ind, menMeans, width, color ='r', yerr=menStd)
ind_ticks = []
for val in ind :
ind_ticks.append(val+(width/2))
xticks(ind_ticks, ('G1', 'G2', 'G3', 'G4', 'G5') )
show()
54
Dans le script ci-dessus nous précisons que nous allons représenter un diagramme à 5 bâtons
(fonction bar) pour des valeurs en x contenues dans ind, des valeurs associées en y contenues dans
menMeans, des erreurs contenues dans menStd. La fonction xticks permet de mettre en place la
légende pour les bâtons.
Figure 18 : Diagramme obtenu par exécution du script ci-dessus
Pour des diagrammes horizontaux, il faudra utiliser la fonction barh dont l'usage est analogue en
considérant une liste des positions en y des barres, une liste des longueurs des barres en x, une
couleur, etc.
Exercice 31 :
Dans un script batons.py, écrire une fonction histo_de qui prend en paramètre un entier
correspondant au nombre de lancés que l'on souhaite simuler et qui affiche le diagramme en bâton
correspondant au nombre de fois où chaque valeur possible est apparue. Le première barre du
graphique représentera donc le nombre de fois où un 1 a été observé lors de la simulation du lancé
du dé.
Autre exemple : Les histogrammes
Les histogrammes constituent un autre grand type de graphiques souvent utiles lorsque l'on veut
représenter des distributions. En Matplotlib, la fonction disponible s'appelle hist .
Un exemple simple :
Dans l'exemple ci-dessous, nous construisons une liste x qui contient des valeurs aléatoires générées
suivant une loi gaussienne (fonction gauss) de moyenne mu et d'écart type sigma.
Nous représentons ensuite l'histogramme de ces valeurs par la fonction hist en précisant que l'on
souhaite 20 barres (paramètres bins), un écart entre les barres de 0.8 (paramètre rwidth) et que l'on
souhaite un histogramme normé (paramètre normed).
La bibliothèque offre la possibilité des représenter plusieurs histogrammes sur un même graphique,
de les juxtaposer ou de les superposer. Pour plus de détails, consulter les différents exemples
disponibles depuis leur site web pour découvrir les paramètres à utiliser.
55
#!/usr/bin/env python
from pylab import hist, savefig, show
from random import gauss
mu, sigma = 200, 25
x = []
for i in range (10000) :
x.append(gauss(mu,sigma))
hist(x, bins=20, normed=1, rwidth=0.8)
savefig('histo.jpg')
show()
Les légendes
Pour rendre un graphique explicite une légende est souvent nécessaire. Voici quelques fonctions
utiles :
•
•
•
•
•
Titre de figure : title
Labels sur les axes : xlabel, ylabel
Encart de légende de couleurs : legend
Valeurs spécifiques sur les axes : xticks , yticks
…
Pour plus de détails sur ces fonctions reportez vous à la documentation en ligne ou utilisez la
fonction help dans Spyder.
En résumé ...
Rappels des fonctions principales présentées dans les pages précédentes.
• matplotlib.pyplot.plot(x,y) : Prend deux listes x et y et trace la courbe (affine par
morceaux) passant par les couples (x[i], y[i]).
• matplotlib.pyplot.scatter(x,y,c='b',marker='o',s='20') : place une série de
points (sans les relier) en (x[i], y[i]). La variable c règle la ou les couleurs utilisées ; marker le symbole
utilisé pour matérialiser les points ; s la taille du symbole.
• matplotlib.pyplot.hist(L,nombre) : L est une liste qui contient les données. C’est le seul
argument obligatoire. Le nombre contient le nombre de barres de l’histogramme.
On peut rajouter l’argument normed='True' pour avoir des proportions plutôt que des effectifs.
• matplotlib.pyplot.show() : Affiche toutes les figures construites jusqu’ici. L’affichage des
figures bloque a priori l’exécution du programme. Autrement dit, si d'autres instructions
apparaissent dans votre programme après l'instruction show(), celles-ci ne seront exécutées qu'après
fermeture des fenêtres correspondantes.
• matplotlib.pyplot.savefig(nom de fichier) : Sauve la figure courante. Le nom du
fichier est donné sous forme de chaine de caractères, et l’extension indique le format de sauvegarde.
o Exemple : matplotlib.pyplot.savefig('Ma_jolie_figure.png').
56
Séance 5
6 Manipulation des Fichiers
Jusqu'ici les données (valeurs) exploitées par nos programmes étaient soit écrites directement dans
le code source, fournies par l'utilisateur au moyen des fonctions input ou raw_input ou encore
générées aléatoirement. Bien que cela permette de développer certaines fonctionnalités et de
réaliser quelques tests, dans la pratique les données qu'un programme peut avoir à traiter ou utiliser
sont stockées sur disque. Une façon de faire cela est de les enregistrer dans un fichier
(éventuellement formaté d'une manière particulière) au même titre que nous enregistrons nos
programmes.
Dans cette partie, nous allons voir comment depuis un programme Python nous pouvons accéder au
contenu d'un fichier ou en créer.
6.1 Ouvrir un fichier
Le type fichier est un type prédéfini de Python comme les entiers, les flottants, les chaînes de
caractères, les listes, ….
En Python, une seule fonction permet plusieurs modes d’ouverture d’un fichier suivant la valeur de
ses arguments et les actions que l’on veut effectuer sur celui-ci :
 lecture
 écriture
 ajout
Exemples pour les principaux modes d'ouverture d’un fichier :
f1 = open("monFichier_1", "r")
f2 = open("monFichier_2", "w")
f3 = open("monFichier_3", "a")
# ouverture en lecture
# ouverture en écriture
# ouverture en ajout
6.2 Fermer un fichier
En Python, il y a une seule méthode de fermeture : la fonction close
f1.close()
#fermeture du fichier f1
Remarque :
Tant que le fichier n'est pas fermé, son contenu n'est pas garanti sur le disque.
Si l’on veut forcer l’écriture sur le disque avant la fermeture du fichier, il faut utiliser la fonction flush
f1.flush()
# force l’écriture sur le disque
6.3 Méthodes de lecture
En Python, il existe différentes méthodes pour lire un fichier :
57
f
s
s
s
s
=
=
=
=
=
open("truc.txt", "r")
f.read()
# lit
f.read(n)
# lit
f.readline()
# lit
f.readlines()
# lit
tout le fichier --> string
au plus n octets --> string
la ligne suivante --> string
tout le fichier --> liste de strings
Exemple de parcours d’un fichier :
f = open("truc.txt", "r")
s = f.readlines()
# lit tout le fichier --> liste de strings
f.close()
for ligne in s :
print ligne
# bon procédé de parcours d'un fichier
Une autre méthode de lecture complète d’un fichier ligne à ligne :
f = open("truc.txt", "r")
for ligne in f :
print ligne
f.close()
Remarque :
La deuxième version est plus légère en lignes de codes que la première mais présente l’inconvénient
de devoir laisser le fichier ouvert tout le temps de traitement de son contenu. L'ouverture d'un
fichier n'en bloque pas l'accès autrement dit, un autre programme peut y accéder et le modifier alors
que le vôtre est en train de lire son contenu ce qui peut être source d'incohérences.
6.4 Méthodes d’écriture :
Pour écrire dans un fichier, le moyen le plus lisible est d’utiliser la méthode write.
Voici un exemple d’utilisation :
f = open("truc.txt", "w")
s = 'toto'
f.write(s)
# écrit la chaîne s dans f
l = ['a', 'b', 'c']
f.writelines(l)
# écrit les chaînes de la liste l dans f
f.close()
6.5 Méthodes seek et tell
Les méthodes seek et tell permettent respectivement de se déplacer au nième caractère d'un fichier et
d'afficher où en est la lecture du fichier, c'est-à-dire quel caractère est en train d'être lu.
filin = open('zoo.txt', 'r')
filin.readline()
# 'girafe\n'
filin.tell()
#7
filin.seek(0)
filin.tell()
filin.readline()
filin.close()
#0
#'girafe\n'
58
On remarque qu'à l'ouverture d'un fichier, le tout premier caractère est considéré comme le
caractère 0 (tout comme le premier élément d'une liste). La méthode seek() permet facilement de
remonter au début du fichier lorsque l'on est arrivé à la fin ou lorsqu'on en a lu une partie.
6.6 Mise en pratique
Les différentes fonctions que vous allez développer dans cette section sont à enregistrer dans un
script fichiers.py qui contiendra le programme principal nécessaire pour les tester.
Exercice 32 :
Étant données les instructions suivantes :
file = open('fichier.txt','r')
lignes = file.readlines()
for i in lignes:
print i
file.close()
Expliquez le résultat associé :
Ceci est la première ligne,
Ceci est la deuxième ligne !
Ceci est la troisième ligne
Ceci est la quatrième et dernière ligne.
Modifiez les instructions pour supprimer les sauts de ligne inutiles.
Exercice 33 :
Écrire une fonction alterne qui à partir de deux fichiers A.txt et B.txt, construit un fichier C.txt qui
contient alternativement une ligne de A, une ligne de B, une ligne de A, et ainsi de suite jusqu'à
atteindre la fin de l'un des deux fichiers originaux.
Complétez ensuite C.txt avec les éléments restant de l'autre.
Exercice 34 :
Écrire une fonction fichier_multi qui génère automatiquement un fichier texte (multi_a_b.txt)
contenant les tables de multiplications de a à b (chacune d'entre elles incluant seulement les dix
premiers termes), a et b étant fournis en paramètres. Vous mettrez en forme votre fichier de sortie
afin que les tables apparaissent nettement. Le nom de votre fichier de sortie devra dépendre des
59
valeurs attribuées à a et à b au moment de l'appel de la fonction. Par exemple, votre fonction devra
permettre de générer un fichier multi_2_10.txt contenant les tables de 2 à 10.
Remarque : la chaine '\n' correspond à un saut de ligne, la chaîne '\t' à une tabulation.
Exercice 35 : Statistiques sur un fichier textuel
Écrire une fonction words calculant la liste des mots d’un fichier.
Écrire une fonction count_words comptant les occurrences de tous les mots dans le texte (une table
associant à chaque mot le nombre de ses occurrences).
Écrire une fonction sum_up qui affiche le nombre de mots différents apparaissant dans le texte, puis
la liste de ces mots ainsi que leur nombre d’occurrences.
Exercice 36 :
Dans cet exercice, nous allons utiliser une sortie partielle de DSSP (Define Secondary Structure of
Proteins), qui est un logiciel d'extraction des structures secondaires de protéines. Ce fichier contient
5 colonnes correspondant respectivement au numéro de résidu, à l'acide aminé, sa structure
secondaire et ses angles phi/psi.
Nous allons travailler sur le fichier dssp.txt (jetez-y un petit coup d'œil en passant...).



Écrivez une fonction extract_cols qui dans un fichier extract_i.txt pour chacune des lignes les
éléments contenu dans la colonne i, i étant fourni en paramètre.
Écrivez une fonction recense_aa qui dans un fichier aa.txt écrit une ligne par acide aminé
présent dans le fichier de départ et ses structures secondaires recensées.
Inversement écrivez une fonction recense_struct qui dans un fichier structs.txt écrit une
ligne par structure secondaire et la liste des acides aminés correspondants.
60
7 Programmation de graphique - fichiers
Pour faire suite à la séance 4, nous allons nous intéresser désormais à la réalisation de graphiques à
partir de données contenues dans des fichiers.
Exercice 37 : Représentation des données du fichier iris.tab
Dans un script iris.py, implémenter les fonctions demandées ci-dessous :
1. Écrire une fonction extract_descripteurs qui, pour un fichier donné d'extension particulière
(.tab), retourne une liste des descripteurs (noms des colonnes) présents dans le fichier.
2. Écrire une fonction extract_values qui, étant donnés un fichier et un descripteur, retourne la
liste des valeurs mesurées pour celui-ci s'il s'agit bien d'un descripteur considéré dans le
fichier fourni.
3. Écrire une fonction scatter_proj qui, étant donnés deux descripteurs et un nom de fichier,
crée le graphique (nuage de points) en 2 dimensions correspondant si cela est possible.
Vous testerez vos différentes fonctions sur le fichier iris.tab.
Exercice 38 : Représentation des données pour la méta-analyse
Une méta-analyse est une démarche statistique combinant les résultats d'une série d'études
indépendantes sur un problème donné. Dans ce cadre, une représentation graphique
particulièrement appréciée consiste à relier les points qui proviennent d’une même expérience afin
de faire ressortir la variabilité entre celles-ci.
À partir du fichier data_meta.txt, écrivez un programme meta.py permettant une représentation,
telle que décrite ci-dessus, des données contenues dans ce fichier.
Le fichier data_meta.txt se compose de trois colonnes séparées par des tabulations. La première
représente le numéro d’expérience, la deuxième la valeur à représenter en x et la troisième la valeur
à représenter en y.
Pour chaque publication, tracer les différentes valeurs connues et reliez-les. Vous obtenez un
graphique semblable à celui-ci-dessous.
61
Dans un deuxième temps, reliez les points par valeurs croissantes sur le premier axe.
Exercice 39 : Représentations « radiales »
Un mode de représentation encore peu disponible dans les outils mais de plus en plus utilisés lorsque
l’on veut faire ressortir des variabilités entre individus (en général en petit nombre) sur les différents
axes qui les caractérisent (aussi en nombre restreint) consiste à représenter les axes par des rayons
équidistants partant de l’origine et les individus par un polygone dans cet espace dont les sommets
correspondent à la valeur prise par l’individu sur chacun des axes.
On obtient une figure semblable à celle ci-dessous :
Où deux individus (un en vert et l’autre en rouge) ont été représentés vis-à-vis des cinq descripteurs
arg0, arg1, arg2, arg3 et arg4.
Les données correspondantes au graphique sont les suivantes :
arg0
1
2
arg1
5
20
arg2
4
5
arg3
16
7
arg4
2
9
Grâce à la bibliothèque Matplotlib, écrire un programme radial.py permettant de générer une telle
représentation pour un nombre de descripteurs et d’individus quelconque.
62
Séance 6
8 Les bases de données et le langage SQL1
Comme nous l'avons vu précédemment, les fichiers nous permettent de stocker des données que
l'on peut utiliser par la suite dans nos programmes et, à l'inverse, nos programmes peuvent
construire des fichiers pour stocker les résultats des traitements effectués.
Néanmoins, suivant la quantité de données et les relations existantes entre elles, les fichiers sont
assez rapidement insuffisants, et avoir recours à d'autres solutions peut être très judicieux.
Considérons l'extrait suivant d'un fichier de données de commandes de clients :
NCLI
Nom
Adresse
Localité
NCOM
Date
NPRO
Qté
Libellé
K111
VANBIST
Lille
30178
25
FERARD
Poitiers
30179
CS262
60
C400
FERARD
Poitiers
30179
PA60
20
S127
VANDERKA
Namur
30182
PA60
30
C400
FERARD
Poitiers
30184
CS464
120
C400
FERARD
Poitiers
30184
PA45
20
F011
PONCELET
Toulouse
30185
CS464
260
F011
PONCELET
Toulouse
30185
PA60
15
F011
PONCELET
Toulouse
30185
PS222
600
C400
FERARD
Poitiers
30186
PA45
3
B512
GILLET
Toulouse
30188
CS464
180
B512
GILLET
14, r. de l'Ete
Toulouse
30188
PA45
22
B512
GILLET
14, r. de l'Ete
Toulouse
30188
PA60
70
B512
GILLET
14, r. de l'Ete
Toulouse
30188
200812-21
200812-22
200812-22
200812-23
200812-23
200812-23
200901-02
200901-02
200901-02
200901-02
200901-03
200901-03
200901-03
200901-03
CS464
C400
180, r.
Florimont
65, r. du
Tertre
65, r. du
Tertre
3, av. des
Roses
65, r. du
Tertre
65, r. du
Tertre
17, Clos des
Erables
17, Clos des
Erables
17, Clos des
Erables
65, r. du
Tertre
14, r. de l'Ete
PH222
92
CHEV. SAPIN
400x6x4
CHEV. SAPIN
200x6x2
POINTE ACIER
60 (1K)
POINTE ACIER
60 (1K)
CHEV. SAPIN
400x6x4
POINTE ACIER
45 (1K)
CHEV. SAPIN
400x6x4
POINTE ACIER
60 (1K)
PL. SAPIN
200x20x2
POINTE ACIER
45 (1K)
CHEV. SAPIN
400x6x4
POINTE ACIER
45 (1K)
POINTE ACIER
60 (1K)
PL. HETRE
200x20x2
Prix
Uni.
220.00
75.00
95.00
95.00
220.00
105.00
220.00
95.00
185.00
105.00
220.00
105.00
95.00
230.00
En observant le contenu de ce fichier, nous pouvons constater rapidement un certain nombre de
redondances. Par exemple, si l'on considère le client C400, nous pouvons constater que son nom et
son adresse apparaissent à plusieurs reprises. En effet, il a passé plusieurs commandes avec parfois
1
Cette partie du support de cours s’appuie sur l’ouvrage "Bases de données. Concepts, utilisation et
développement" de Jean-Luc Hainaut, paru en 2009 aux éditions Dunod.
63
plusieurs produits. De manière analogue, un même produit commandé à plusieurs reprises aura son
libellé noté pour chaque achat. Tout ceci est nécessaire lorsque l'on veut stocker ces données dans
un fichier. Néanmoins cela est rapidement coûteux. Ici, il ne s'agit que d'un bref exemple considérant
uniquement quelques clients et quelques produits. Imaginez le volume de données analogues
qu'Amazon ou la Fnac possèdent.
La particularité des données présentées dans cet exemple par rapport à ce que l'on a pu voir dans les
séances précédentes est que nos données sont ici "liées" : un client est à "rattacher" à un certain
nombre de commandes qui elles-mêmes concernent un certain nombre de produits. Certaines de ces
informations sont propres à une entité particulière par exemple l'adresse pour une personne ou le
libellé d'un produit en revanche d'autres marquent les liens qui les unissent par exemple le numéro
de commande permet de retrouver tous les produits achetés lors d'un même achat.
Lorsque l'on est confronté à ce cas de figure il devient préférable de stocker ces données dans ce que
l'on appelle une base de données.
Par ailleurs, en dehors du problème de redondance, il n'est pas aisé avec un tel fichier de déterminer
rapidement et automatiquement par exemple tous les produits commandés par un client donné.
Les bases de données sont des outils de plus en plus fréquemment utilisés. Elles permettent de
stocker des données nombreuses dans un seul ensemble bien structuré, d’éviter le plus souvent les
doublons, d’assurer la cohérence des informations qu’elles contiennent et fournissent des moyens
d'interrogation performants répondant ainsi à toutes nos réserves vis-à-vis de l'usage de fichiers pour
des données "liées".
Il existe de nombreux systèmes de bases de données souvent construits sur une architecture
complexe dite client-serveur (MySQL, PostgresSQL, Access, etc.). Pour ce module nous avons choisi
d'utiliser SQLite, une bibliothèque écrite en langage C, qui s’intègre directement aux programmes
que l'on souhaite développer. SQLite n'offre bien entendu pas autant de fonctionnalités que les
systèmes plus complexes néanmoins c'est un bon point de départ pour découvrir les bases de
données puisqu'il va nous permettre d'aborder toutes les notions fondamentales sans se charger de
contraintes techniques inutiles pour le moment.
8.1 Quelques définitions
Une base de données est constituée d'un ensemble de tables.
Une table contient une collection/suite de lignes, aussi appelées enregistrements ; une par entité
considérée.
Une ligne d'une table est une suite de valeurs, chacune d'un type (nature) déterminé. Une ligne
regroupe les données relatives à une entité considérée dans des colonnes aussi appelées champs.
Toutes les lignes d'une table ont la même structure (même nombre de colonnes).
Une colonne est définie par son nom et le type des valeurs qu'elle peut contenir. Elle peut être
obligatoire ou non c'est-à-dire que l'on peut imposer d'avoir une valeur pour chaque entité ou au
contraire accepter la valeur particulière NULL (ou None suivant les systèmes) qui représente
l'absence de valeur pour cette colonne et l'entité considérée.
En SQLite, les types de valeurs qui pourront être gérés sont les suivants :
 None pour l'absence de valeur.
 INTEGER pour les entiers.
 REAL pour les nombres réels.
 TEXT pour les chaînes de caractères.
 BLOB pour les données brutes.
64
Dans notre exemple précédent, on peut lister la présence de trois groupes d'entités : des clients, des
commandes et des produits. Observons par ailleurs les informations dont on disposait :
NCLI
Nom
Adresse
Localité
NCOM
Date
NPRO
Qté
Libellé
Prix Uni.
Les colonnes NCLI, Nom, Adresse et Localité se rapportent aux clients, les informations NCOM et
Date aux commandes et enfin NPRO, Libellé et Prix Uni aux produits. Il semblerait donc assez naturel
de créer trois tables pour stocker ces informations avec, au moins, les colonnes citées
précédemment.
Tableau 2 : Table des clients
NCLI
K111
C400
S127
F011
B512
Nom
VANBIST
FERARD
VANDERKA
PONCELET
GILLET
Adresse
180, r. Florimont
65, r. du Tertre
3, av. des Roses
17, Clos des Erables
14, r. de l'Ete
Localité
Lille
Poitiers
Namur
Toulouse
Toulouse
Tableau 3 : Table des commandes
NCOM
30178
30179
30182
30184
30185
30186
30188
Date
2008-12-21
2008-12-22
2008-12-23
2008-12-23
2009-01-02
2009-01-02
2009-01-03
Tableau 4 : Table des produits
NPRO
CS464
CS262
PA60
PA45
PS222
PH222
Libellé
CHEV. SAPIN 400x6x4
CHEV. SAPIN 200x6x2
POINTE ACIER 60 (1K)
POINTE ACIER 45 (1K)
PL. SAPIN 200x20x2
PL. HETRE 200x20x2
Prix Uni.
220.00
75.00
95.00
105.00
185.00
230.00
Seules les lignes distinctes ont été conservées, les autres n'apportant pas d'informations
supplémentaires dans ce contexte.
Pour être équivalent à notre fichier de départ (c'est-à-dire permettre de reconstruire chacune de ses
lignes), il nous faut désormais considérer les liens qui existent entre les entités.
Un premier lien exprime le fait qu'une commande est passée par un client. C'est un lien de nature
assez simple (dit 1-N, car elle peut faire correspondre à une entité (e.g. un client) plusieurs entités
65
(e.g. des commandes)). Pour réaliser ce lien, il est suffisant de rajouter une colonne dans la table des
commandes afin d'y recenser les numéros de clients correspondants comme ceci :
Tableau 5 : Table des commandes complétée pour faire le lien avec les clients
NCOM
30178
30179
30182
30184
30185
30186
30188
NCLI
K111
C400
S127
C400
F011
C400
B512
Date
2008-12-21
2008-12-22
2008-12-23
2008-12-23
2009-01-02
2009-01-02
2009-01-03
Ainsi, depuis une commande, on pourra se référer à la table des clients par le numéro NCLI (qui doit
être unique).
Un autre lien à prendre en compte dans nos données de départ vient du fait qu'une commande
correspond à l'achat d'un certain nombre de produits dans une certaine quantité stockée
initialement dans le champ Qté que nous n'avions pu rattacher jusque là à aucune entité.
Nous sommes confrontés ici à un lien dit N-N car une commande peut correspondre à plusieurs
produits et un produit peut apparaitre dans plusieurs commandes. Dans ce cas, il nous faut créer une
nouvelle table, que l'on pourrait nommer detail, qui va faire le "pont" entre les tables des
commandes et des produits et dans laquelle une ligne servira à exprimer qu'un produit en particulier
a été commandé dans une commande particulière.
Soit la table suivante :
Tableau 6 : Table faisant le lien entre les commandes et les produits
NCOM
30178
30179
30179
30182
30184
30184
30185
30185
30185
30186
30188
30188
30188
30188
NPRO
CS464
CS262
PA60
PA60
CS464
PA45
CS464
PA60
PS222
PA45
CS464
PA45
PA60
PH222
Qté
25
60
20
30
120
20
260
15
600
3
180
22
70
92
Ainsi nous avons au niveau des données stockées un équivalent de notre fichier de départ et nous
allons pouvoir profiter des fonctionnalités offertes par les systèmes de base de données.
66
Exercice 40 :
Vérifiez qu'il y a bien équivalence entre le contenu du fichier et les tableaux de 2 à 6 ci-dessus pour la
commande 30185.
8.2 La notion de clé
8.2.1
Clé primaire
Une ligne dans une table regroupe des données sur une entité. Une des propriétés importantes dans
une table est de pouvoir identifier de manière certaine (unique) une ligne à l'aide d'un identifiant ou
clé (key en anglais) qui peut être composée de plusieurs colonnes.
Parmi les clés possibles pour une table donnée l'une est déclarée comme clé primaire (primary key
en anglais). À partir de là, le système en garantira l'unicité c'est-à-dire qu'il refusera l'insertion d'une
nouvelle ligne dans une table si la valeur de sa clé primaire est déjà présente. C'est ce que l'on
appelle une contrainte d'unicité. Bien que non imposée, la déclaration d'une clé primaire pour toute
table est fortement recommandée. Sans elle, on ne peut plus garantir l'identification d'une ligne de
manière certaine.
Dans notre exemple précédent, il serait naturel de définir par exemple NCLI comme clé primaire de
la table des clients et le couple (NCOM,NPRO) comme clé primaire de la table des détails afin de
garantir que pour une commande donnée un produit particulier ne puisse être considéré plus qu'une
seule fois.
Exercice 41 :
Que peut-on choisir comme clé primaire pour les autres tables ?
8.2.2
Clé étrangère
Dans une première table donnée (dite "table fille"), une information qui permet de se rapporter à
une deuxième table (dite "table parent") c'est-à-dire qui contient des valeurs de la clé primaire de
cette seconde table est appelée clé étrangère (foreign key en anglais) pour la première table.
Toujours sur notre exemple, le numéro de commande NCOM dans la table des détails est une clé
étrangère qui permet de se référer aux commandes.
67
Exercice 42 :
Faîtes la liste des clé étrangères présentent dans chaque table de la base de données ci-dessus
concernant des clients et leurs commandes.
8.3 Contraintes d'intégrité
Les colonnes obligatoires, les clés primaires et les clés étrangères imposent des contraintes sur le
contenu de la base de données qui doivent être satisfaites en permanence. Ces différentes
contraintes dites d'intégrité seront donc vérifiées lors de chaque tentative de modification de la base
de données.
Contraintes sur les colonnes obligatoires
Si une colonne est déclarée obligatoire (toute entité doit posséder une valeur pour cette colonne),
alors, lors de l'ajout ou de la modification d'une ligne, une valeur différente de NULL (ou None) devra
être fournie. Dans le cas contraire l'opération sera rejetée.
Contraintes sur les clés primaires (contraintes d'unicité)
Une clé primaire correspond, comme on l'a vu précédemment, à une contrainte d'unicité. C'est
pourquoi un ajout ou une modification d'une ligne ne seront autorisés que s'ils ne remettent pas en
cause cette propriété c'est-à-dire seulement si la nouvelle valeur de clé proposée est distincte de
toutes celles déjà présentes.
Sur notre exemple précédent, il nous serait donc impossible d'ajouter un nouveau client avec un
numéro de client égal à K111 puisque ce numéro est déjà présent pour le client VANBIST.
Contraintes sur les clés étrangères (contraintes référentielles)
Les clés étrangères imposent également des contraintes. Celles-ci, comme nous l'avons vu, ont pour
rôle de faire le lien entre plusieurs tables en exploitant les propriétés des clés primaires. Considérons
les tables clients et commandes de notre exemple. À partir du moment où une commande est
enregistrée pour le client K111 alors ce client ne pourra pas être supprimé, ou son numéro de client
modifié, sans rendre la base de donnée incohérente.
Plus généralement, la suppression directe dans la table parent (ici la table client) d'une ligne
référencée dans la table fille (commande) sera refusée. Pour conserver une base de données
cohérente si les données doivent être supprimées, la stratégie consiste à commencer par supprimer
les lignes nécessaires dans la table fille avant de réaliser les suppressions dans la table parent.
Ainsi si je veux pouvoir supprimer le client K111, il me faudra d'abord supprimer la commande 30178
et avant cela pour les mêmes raisons les lignes de la table des détails qui s'y rapportent. Ici, une seule
ligne qui concerne le produit CS464.
68
Exercice 43 :
Que faudrait-il faire pour pouvoir supprimer les clients F011 et C400 ?
8.4 Schéma et contenu
Une base de données est composée de deux parties distinctes : son schéma et son contenu.
Le schéma d'une base de données spécifie la liste des tables et pour chacune son nom, la liste de ses
colonnes (champs), sa clé primaire et s'il y a lieu sa ou ses clés étrangères. Pour chaque colonne, il
est également précisé son nom, son type et si elle est ou non obligatoire.
Le contenu d'une base de données est dépendant de l'instant considéré et est l'ensemble des lignes
présentes dans chacune de ses tables.
Le contenu d'une base de données réelle compte généralement plusieurs milliers ou millions de
lignes et peut évoluer à chaque instant. En revanche, son schéma doit contenir un nombre limité
d'éléments et être assez stable dans le temps.
Il existe plusieurs conventions graphiques de représentation d’un schéma de BD, parmi lesquelles les
plus utilisées sont les suivantes :
1. Une table est représentée le plus souvent par une boîte dont le premier compartiment indique le
nom de la table et ensuite les noms de ses colonnes en liste verticale.
2. La clé primaire est soit soulignée d’un trait continu, soit elle est indiquée en gras, soit elle est
spécifiée par la clause “id :”.
3. Une clé étrangère est soit soulignée d’un trait pointillé, soit spécifiée par la clause “ref :”.
4. Une contrainte référentielle est représentée par une flèche qui part du nom de la colonne qui est
une clé étrangère et qui pointe vers la clé primaire référencée dans la table cible.
Figure 19 : Schéma de la base de données obtenu pour notre exemple traitant de clients et de commandes
69
On considère désormais la base de données nommée client_commande dont le schéma pus
complet que celui étudié jusqu'à présent est fourni ci-dessous ainsi que le contenu de ses tables à
l'instant qui nous intéresse.
Figure 20 : Schéma de la base de données client_commande
Tableau 7 : Contenu de la table client
NCLI
B062
B112
B332
B512
C003
C123
C400
D063
F010
F011
F400
K111
K729
L422
S127
S712
NOM
GOFFIN
HANSENNE
MONTI
GILLET
AVRON
MERCIER
FERARD
MERCIER
TOUSSAINT
PONCELET
JACOB
VANBIST
NEUMAN
FRANCK
VANDERKA
GUILLAUME
ADRESSE
72, r. de la Gare
23, a. Dumont
112, r. Neuve
14, r. de l'Ete
8, ch. de la Cure
25, r. Lemaitre
65, r. du Tertre
201, bvd du Nord
5, r. Godefroid
17, Clos des Erables
78, ch. du Moulin
180, r. Florimont
40, r. Bransart
60, r. de Wepion
3, av. des Roses
14a, ch. des Roses
Tableau 9 : Contenu de la table commande
NCOM
30178
30179
30182
30184
30185
30186
30188
NCLI
K111
C400
S127
C400
F011
C400
B512
DATECOM
2008-12-21
2008-12-22
2008-12-23
2008-12-23
2009-01-02
2009-01-02
2009-01-03
LOCALITE
Namur
Poitiers
Geneve
Toulouse
Toulouse
Namur
Poitiers
Toulouse
Poitiers
Toulouse
Bruxelles
Lille
Toulouse
Namur
Namur
Paris
CAT
B2
C1
B2
B1
B1
C1
B2
NULL
C1
B2
C2
B1
NULL
C1
C1
B1
COMPTE
-3200.00
1250.00
0.00
-8700.00
-1700.00
-2300.00
350.00
-2250.00
0.00
0.00
0.00
720.00
0.00
0.00
-4580.00
0.00
Tableau 8 : Contenu de la table
detail
NCOM
30178
30179
30179
30182
30184
30184
30185
30185
30185
30186
30188
30188
30188
30188
NPRO
CS464
CS262
PA60
PA60
CS464
PA45
CS464
PA60
PS222
PA45
CS464
PA45
PA60
PH222
QCOM
25
60
20
30
120
20
260
15
600
3
180
22
70
92
Tableau 10 : Contenu de la table produit
NPRO
CS262
CS264
CS464
PA45
PA60
PH222
PS222
LIBELLE
CHEV. SAPIN 200x6x2
CHEV. SAPIN 200x6x4
CHEV. SAPIN 400x6x4
POINTE ACIER 45 (1K)
POINTE ACIER 60 (1K)
PL. HETRE 200x20x2
PL. SAPIN 200x20x2
PRIX
75.00
120.00
220.00
105.00
95.00
230.00
185.00
QSTOCK
45
2690
450
580
134
782
1220
70
Exercice 44 :
Étant données ces informations répondez aux questions suivantes :
1. Combien de lignes existent dans chaque table ?
2. Quel est le prix du produit 'POINTE ACIER 60 (1K)' ? Combien en reste-t-il en stock ?
3. Quels sont les noms des clients de catégorie 'B1' ?
4. Pour le client 'FERARD', combien a-t-il passé de commandes ?
5. Pour le client 'VANBIST', combien a-t-il passé de commandes ?
6. Quel(s) produits(s) a commandé le client 'VANBIST' et en quelle quantité ?
8.5 Le langage SQL (Structured Query Language)
Présenté pour la première fois en 1973, ce langage a rapidement été adopté comme standard. Une
instruction SQL constitue une requête (query en anglais), c'est-à-dire une opération que le système
de base de données doit réaliser.
8.5.1 Consulter les données stockées dans une base de données existante
Suivant les besoins la consultation (extraction) de données stockées dans une base de données fera
intervenir différents mots clés du langage SQL.
Extractions simple
A minima cela nécessitera le mot clé SELECT pour préciser de quelle(s) colonne(s) nous souhaitons
obtenir des valeurs et le mot clé FROM pour indiquer de quelle table.
La syntaxe générique est la suivante :
SELECT colonne_souhaitée_1, ..., colonne_souhaitée_n
FROM table_souhaitée
Exemple :
Si l'on souhaite, pour toutes les lignes de la table client de notre base de données clientcommande, obtenir les valeurs des colonnes NCLI, NOM et LOCALITE, nous utiliserons la requête
suivante :
SELECT NCLI, NOM, LOCALITE
FROM client
71
Lorsque l'on souhaite obtenir les valeurs pour toutes les colonnes disponibles, il ne sera pas
nécessaire de les lister toutes. Nous utiliserons le symbole *. Pour la table client nous aurions donc
à écrire:
SELECT *
FROM client
Extractions avec restrictions
Souvent ce ne sont pas toutes les lignes qui nous intéressent mais uniquement celles qui
correspondent à un critère donné, à une condition qui est vérifiée. Pour cela nous aurons recours au
mot clé WHERE suivi de la condition à vérifier.
La syntaxe appropriée sera alors :
SELECT colonne_souhaitée_1, ..., colonne_souhaitée_n
FROM table_souhaitée
WHERE condition_est_vraie
Une condition étant de type booléen (valant soit vrai soit faux) elle pourra être obtenue par l'usage
de comparateur. En SQL, nous avons à notre disposition les opérateurs suivants :
=
>
<
<>
>=
<=
égal à
plus grand que
plus petit que
différent de
plus grand ou égal à
plus petit ou égal à
L’interprétation de ces relations est bien connue pour les valeurs numériques.
Pour les chaînes de caractères, l’expression chaine_1 < chaine_2 pour toutes chaînes chaine_1 et
chaine_2, s’interprète comme chaine_1 est plus petite que chaine_2 selon l’ordre lexicographique
(celui du dictionnaire).
Attention : la casse est prise en compte autrement dit le caractère "a" n’est pas égal au caractère
"A".
Les comparaisons peuvent être "combinées" à l'aide d'opérateurs logiques pour obtenir des
conditions complexes. Nous disposons en SQL des opérateurs suivants :
AND
conjonction (et)
OR
disjonction (ou)
NOT
négation (opposé)
Lorsqu’une expression complexe comporte plusieurs opérateurs, les priorités des opérateurs
déterminent l’ordre d’exécution des opérations. Les règles qui s'appliquent ici sont identiques à
celles du langage Python (cf. section 3.1.6).
Exemple :
SELECT NCLI, NOM
FROM client
WHERE LOCALITE = 'Toulouse'
72
La requête ci-dessus nous fournira les valeurs des colonnes NCLI et NOM de la table client pour
toutes les lignes dont la valeur pour la colonne LOCALITE est égale à Toulouse.
Exercice 45 :
NCLI
B062
B112
B332
B512
C003
C123
C400
D063
F010
F011
F400
K111
K729
L422
S127
S712
NOM
GOFFIN
HANSENNE
MONTI
GILLET
AVRON
MERCIER
FERARD
MERCIER
TOUSSAINT
PONCELET
JACOB
VANBIST
NEUMAN
FRANCK
VANDERKA
GUILLAUME
ADRESSE
72, r. de la Gare
23, a. Dumont
112, r. Neuve
14, r. de l'Ete
8, ch. de la Cure
25, r. Lemaitre
65, r. du Tertre
201, bvd du Nord
5, r. Godefroid
17, Clos des Erables
78, ch. du Moulin
180, r. Florimont
40, r. Bransart
60, r. de Wepion
3, av. des Roses
14a, ch. des Roses
LOCALITE
Namur
Poitiers
Geneve
Toulouse
Toulouse
Namur
Poitiers
Toulouse
Poitiers
Toulouse
Bruxelles
Lille
Toulouse
Namur
Namur
Paris
CAT
B2
C1
B2
B1
B1
C1
B2
NULL
C1
B2
C2
B1
NULL
C1
C1
B1
COMPTE
-3200.00
1250.00
0.00
-8700.00
-1700.00
-2300.00
350.00
-2250.00
0.00
0.00
0.00
720.00
0.00
0.00
-4580.00
0.00
En supposant qu'à l'instant qui nous intéresse la table client est celle donnée ci-dessus, quel est le
résultat de la requête précédente ?
Opérateurs spécifiques
Une condition peut également porter sur la présence de la valeur NULL (ou None) :
CAT is null
CAT is not null
ou sur l’appartenance ou non à un ensemble :
CAT in ( 'C1', 'C2', 'C3')
LOCALITE not in ( 'Toulouse', 'Namur', 'Breda')
ou encore sur la présence de certains caractères dans une valeur :
CAT like '_1'
ADDRESSE like '%Neuve%'
Dans les deux dernières conditions, le signe '_' désigne un caractère quelconque et '%' désigne toute
suite de caractères, éventuellement vide.
73
Extractions sans doublons
Pour éliminer les lignes en double dans le résultat d’une requête, on utilise le mot clé distinct.
Exemple :
SELECT distinct LOCALITE
FROM client
Extractions ordonnées
Il est possible d’ordonner les résultats d’une requête grâce au mot clé ORDER BY:
SELECT liste_colonnes
FROM nom_table
WHERE condition
ORDER BY liste_colonnes ASC|DESC
Par défaut, le classement se fait par ordre ascendant (ASC) des valeurs. On peut également spécifier
explicitement un ordre ascendant (ASC) ou descendant (DESC).
Exemple: Pour la base de données client_commande les lignes résultant de la requête ci-dessous
vont apparaître classées par ordre alphabétique croissant sur le nom des localités.
SELECT *
FROM client
WHERE CAT is not null
ORDER BY LOCALITE
Lorsqu'une liste de critères de tri est spécifiée, l'ordre des éléments marque les priorités du tri : on
considère d'abord l'élément le plus à gauche dans la liste, puis à valeurs égales on considère
l'élément à sa droite et ainsi de suite.
Exemple :
SELECT *
FROM client
ORDER BY LOCALITE, CAT
Par cette requête, nous obtiendrons toutes les informations disponibles sur les clients classés par
localité, puis dans chaque localité, classés par catégorie.
Exercice 46 :
Pour chaque requête donnée ci-dessous expliquez ce qu’elle fait et trouvez la réponse attendue
compte tenu des tableaux 8 à 11.
SELECT *
FROM produit
WHERE LIBELLE LIKE '%ACIER%'
ORDER BY PRIX
74
SELECT NCOM, DATECOM
FROM commande
WHERE NCLI = 'C400'
AND DATECOM < '2009-01-01'
SELECT NOM, ADRESSE, COMPTE
FROM client
WHERE COMPTE > 0
AND (CAT = 'C1' OR LOCALITE = 'Paris')
SELECT NOM, ADRESSE, COMPTE
FROM client
WHERE COMPTE > 0 OR CAT = 'C1' AND LOCALITE = 'Paris'
Dans l’expression COMPTE > 0 OR CAT = 'C1' AND LOCALITE = 'Paris' dans quel ordre
sont évalués les opérateurs logiques OR et AND ?
Réponse 1 : ((COMPTE > 0 OR CAT = 'C1') AND LOCALITE = 'Paris')
ou
Réponse 2 : (COMPTE > 0 OR (CAT = 'C1' AND LOCALITE = 'Paris'))
Justifiez votre réponse.
Exercice 47 :
En utilisant l'application AgroPythia, que vous trouverez sur la page du cours, vérifiez vos réponses
pour l'Exercice 46. Pour éviter de les retaper, celles-ci ont été retranscrites dans le fichier
requetes_client_commande.sql. Vous pourrez ainsi procéder par copier-coller.
Exercice 48 :
Toujours à l'aide de l'application AgroPythia, écrivez les requêtes répondant aux demandes
suivantes :
1. Extraire en ordre alphabétique la liste des localités où habitent les clients.
2. Affichez les commandes passées pendant les dix derniers jours de l’année 2008.
3. Affichez le stock de chaque produit dont le libellé contient 'sapin'.
4. Affichez les produits dont le prix est inférieur à 200 et le stock est supérieur à 150.
5. Affichez le numéro, le nom et la localité des clients de catégorie B1 n’habitant pas à Paris.
75
Vous
conserverez
vos
réponses en copiant-collant vos requêtes dans le fichier
requetes_client_commande.sql.
Remarque : Vous pouvez également les récupérer depuis le fichier de log généré lors de votre usage
de l'application AgroPythia .
Extractions sur plusieurs tables
Pour profiter des liens qui existent entre les tables d'une base de données, nous allons avoir recours
à ce que l'on appelle des jointures qui de manière dynamique vont nous permettre de mettre en
correspondance les éléments des différentes tables liées entre elles suivant une règle que l'on devra
préciser. Autrement dit nous aurons à préciser la nature des liens qui les unissent.
Syntaxe générale :
SELECT liste_colonnes
FROM nom_table_1, nom_table_2, nom_table_3, ..., nom_table_n
WHERE
col_FK_1 = col_PK_2
AND col_FK_31 = col_PK_2
AND col_FK_32 = col_PK_n
AND ...
AND condition
Ci-dessus, nous considérons n tables liées entre elles. Nous aurons donc à préciser n-1 liens par des
conditions du type col_FK_i = col_PK_j où col_FK_i désigne la colonne dans la table
nommée nom_table_i qui est une clé étrangère pour celle-ci lui permettant de se relier à la table
nommée nom_table_j dont la clé primaire est nommée col_PK_j.
Notre requête générique ci-dessus fait donc état des liens suivants :
Figure 21 : Schéma partiel de la base de données considérée dans l'exemple ci-dessus
Comme indiqué dans la requête générique ci-dessus, aux différentes conditions de jointure
nécessaires, il est possible, comme nous le faisions jusque là, d'ajouter d'autres conditions qui seront
combinées toujours par des opérateurs logiques.
76
Exemple :
SELECT NCOM, DATECOM, NOM, LOCALITE
FROM commande, client
WHERE commande.NCLI = client.NCLI
La requête ci-dessus, en considérant nos données initiales sur les clients et leurs commandes, nous
fournira en plus du numéro et de la date contenus dans la table des commandes, le nom et la localité
du client concerné, des informations qui proviennent quant à elles de la table des clients.
Tableau 11 : Résultat fourni pour la requête ci-dessus et les données considérées en début de chapitre
NCOM
30178
30179
30182
30184
30185
30186
30188
Date
2008-12-21
2008-12-22
2008-12-23
2008-12-23
2009-01-02
2009-01-02
2009-01-03
Nom
VANBIST
FERARD
VANDERKA
FERARD
PONCELET
FERARD
GILLET
Localité
Lille
Poitiers
Namur
Poitiers
Toulouse
Poitiers
Toulouse
Remarques :
Si les deux tables ont des colonnes qui ont le même nom, il faut lever l’ambiguïté associée et préciser
à quelle table appartient la colonne que l'on souhaite obtenir, en utilisant la syntaxe suivante :
nom_table.nom_colonne
L’ordre des noms des tables dans la clause FROM ainsi que l’ordre des conditions dans la clause
WHERE n’a pas d’importance.
Quelques détails sur le mécanisme de jointure
Détaillons un peu ce mécanisme lors d'une jointure faisant intervenir deux tables. Le résultat est
dans ce cas obtenu comme suit :
1. On construit dynamiquement une table temporaire en couplant chaque ligne de la première table
avec chaque ligne de la seconde. Ainsi, pour la requête ci-dessus nous considérons la table des
clients (4 colonnes et 5 lignes) et la table des commandes (3 colonnes et 7 lignes). Nous
construisons donc à cette étape une table qui contiendra 7 colonnes (juxtaposition de colonnes
des deux tables considérées) et 35 lignes (les 5 lignes des clients ayant été associées
systématiquement aux 7 lignes des commandes).
2. On sélectionne, parmi les lignes ainsi obtenues, celles qui vérifient la condition de jointure. Dans
notre exemple nous ne conserverons que les lignes qui mettent bien en correspondance un client
avec ses propres commandes.
3. Si d'autres conditions sont considérées, les lignes seront encore filtrées suivant ces conditions.
4. Enfin, seules les valeurs des colonnes ou éventuellement des calculs demandés seront fournies en
résultat.
77
Exercice 49 : Premières jointures
Pour chaque requête donnée ci-dessous expliquez ce qu’elle fait et trouvez la réponse attendue par
rapport au contenu des tableaux 8 à 11.
Attention : Les requêtes peuvent être incomplètes ou fausses !
SELECT NOM, NCOM
FROM client, commande
WHERE client.NCLI = commande.NCLI
AND LOCALITE = 'Toulouse'
SELECT LIBELLE, PRIX, QCOM
FROM detail, produit
WHERE detail.NPRO = produit.NPRO
AND NCOM = '30188'
SELECT NOM, commande.NCOM, detail.NCOM, LIBELLE, PRIX, QCOM
FROM client, commande, detail, produit
WHERE client.NCLI = commande.NCLI
AND detail.NPRO = produit.NPRO
AND commande.NCOM = '30188'
Exercice 50 :
En utilisant à nouveau l'application AgroPythia vérifiez vos réponses à l'Exercice 49. Pour éviter de
les retaper, celles-ci ont été retranscrites dans le fichier requetes_client_commande.sql. Vous
pourrez ainsi procéder par copier-coller.
Exercice 51 : Requêtes avec jointures
Après avoir identifié les tables à consulter et les conditions de jointure nécessaires, utilisez
l'application AgroPythia pour écrire les requêtes SQL qui répondent aux questions ci-dessous.
Copier celles-ci dans le fichier requetes_client_commande.sql afin de les conserver.
1. Affichez tous les produits commandés (nom, prix, quantité) par le client 'B512'.
2. Affichez tous les produits (nom, prix, quantité) commandés par le client 'FERARD', par ordre
croissant de numéro de commande puis par ordre alphabétique sur le nom de produit.
3. Quels clients ont procédé à des commandes en 2009 ?
4. Quels sont les noms des produits qui ont été commandés les dix derniers jours de l’année
2008 ?
5. Quels sont les numéros des produits qui ont été commandés à la fois le 23/12/2008 et le
2/01/2009 ?
78
6. Quels sont les numéros des produits qui ont été commandés le 2/01/2009, mais pas le
23/12/2008 ? Et quels sont les noms de ces produits ?
Extractions et opérations sur les valeurs
La clause SELECT permet aussi de spécifier des données calculées ou encore des constantes.
Exemple :
SELECT NPRO, ’ = ’, 1.20*PRIX*QSTOCK AS ”mont ant TVA”
FROM produit
Le résultat de la requête ci-dessus contient autant de lignes que de produits présents dans la table
produit et pour chacun d'eux leur numéro associé à la valeur du stock TTC.
SQLite offre différentes fonctions permettant de répondre à bon nombre de besoins.
Reportez-vous à la page https://www.sqlite.org/lang_corefunc.html pour une liste de celles-ci.
Fonctions agrégatives
Il existe des fonctions prédéfinies qui donnent une valeur "agrégée" calculée pour les lignes
sélectionnées par une requête select. Elles sont documentées à l'adresse suivante :
https://www.sqlite.org/lang_aggfunc.html.
Voici quelques exemples :
 count(*) compte le nombre de lignes trouvées,
 count(nom_colonne) compte le nombre de valeurs trouvées de la colonne (équivalent au
nombre de lignes),
 avg(nom_colonne) calcule la moyenne des valeurs de la colonne,
 sum(nom_colonne) calcule la somme des valeurs de la colonne,
 min(nom_colonne) donne le minimum des valeurs de la colonne,
 max(nom_colonne) donne le maximum des valeurs de la colonne.
Il est à noter que ces fonctions, à l’exception de la première (count), ne considèrent que les valeurs
non NULL de la colonne. En outre, chaque valeur est prise en compte, même si elle apparaît plusieurs
fois.
Exemple :
SELECT count(*)
FROM client
La requête ci-dessus permet d'obtenir le nombre de lignes de la table nommée client.
SELECT count(distinct NCLI)
FROM commande
La requête ci-dessus donnera le nombre de clients différents ayant passé au moins une commande.
Attention :
SELECT MAX(DATECOM)
FROM commande
79
La requête ci-dessus affiche la date de la dernière commande enregistrée dans la table commande (la
plus grande), en revanche la requête ci-dessous est fausse.
SELECT MAX(DATECOM), NCOM
FROM commande
En effet, elle ne permet pas de récupérer le numéro de cette dernière commande ! En d'autres
termes le système n'est pas capable de retenir à quelle ligne le max se trouvait et lui associer ainsi les
autres valeurs contenues dans sa ligne.
Par cela, il faut raisonner en deux temps :
 trouver le maximum
 puis trouver la ligne où se trouve le maximum identifié.
Cela correspond à faire ce que l'on appelle une sous-requête :
SELECT NCOM, DATECOM
FROM commande
WHERE DATECOM in (
SELECT MAX(DATECOM)
FROM commande
)
Groupements
Le mot clé Group By permet de créer des groupements de lignes en fonction d'une liste de critères.
Il fournit une ligne par groupe avec les informations du dernier représentant de chaque groupe.
Par exemple, la requête suivante nous donne les informations du dernier client de chaque catégorie.
SELECT *
FROM client
GROUP BY cat
Compte tenu de l'état considéré pour notre base de données client-commande, les sorties
correspondantes seraient les suivantes :
NCLI
K729
S712
F011
S127
F400
NOM
NEUMAN
GUILLAUME
PONCELET
VANDERKA
JACOB
ADRESSE
40, r. Bransart
14a, ch. des Roses
17, Clos des Erables
3, av. des Roses
78, ch. du Moulin
LOCALITE
Toulouse
Paris
Toulouse
Namur
Bruxelles
CAT
None
B1
B2
C1
C2
COMPTE
0.0
0.0
0.0
-4580.0
0.0
Ce type de résultats est rarement utile.
En revanche, associée à une fonction agrégative, la clause Group By permet au sein d'une requête
d'effectuer des traitements de nature statistique.
Cela permet, par exemple, de savoir pour chaque catégorie de clients combien se situent dans telle
ou telle catégorie.
SELECT count(*), cat
FROM client
GROUP BY cat
80
Ce qui nous donnerait :
count(*)
2
4
4
5
1
cat
None
B1
B2
C1
C2
Le groupement pouvant se faire sur plusieurs critères, cela nous permettrait également de
déterminer combien de clients d'une certaine catégorie habitent dans une certaine ville et ainsi de
suite.
SELECT count(*), cat, localite
FROM client
GROUP BY cat, localite
Tout ceci peut bien entendu être combiné avec l'utilisation de jointures ou autres fonctions
agrégatives pour répondre à des questions plus poussées.
Exercice 52 : Fonction agrégatives
Pour chaque requête donnée ci-dessous expliquez ce qu’elle fait et trouvez la réponse attendue
toujours par rapport aux tableaux 8 à 11.
SELECT nom, max(COMPTE)
FROM client
SELECT count(distinct commande.NCOM)
FROM commande, detail, produit
WHERE commande.NCOM = detail.NCOM
AND detail.NPRO = produit.NPRO
AND LIBELLE like '%ACIER%'
SELECT sum(QCOM*PRIX) as MONTANT
FROM detail, produit
WHERE detail.NPRO = produit.NPRO
AND LIBELLE like '%ACIER%'
81
SELECT LIBELLE, PRIX as PrixUnitaire, QCOM, QCOM*PRIX as SousTotal
FROM detail, produit
WHERE detail.NPRO = produit.NPRO
AND NCOM = '30179'
Exercice 53 :
En utilisant à nouveau l'application AgroPythia vérifiez vos réponses à l'Exercice 52. Pour éviter de
les retaper, celles-ci ont été retranscrites dans le fichier requetes_client_commande.sql. Vous
pourrez ainsi procéder par copier-coller.
Exercice 54 Requêtes avec agrégations
Utilisez l'application AgroPythia pour écrire les requêtes SQL qui répondent aux questions suivantes
et copiez-les dans le fichier requetes_client_commande.sql.
1.
2.
3.
4.
5.
8.5.2
Calculez le nombre de produits (références) dont le libellé contient 'sapin'.
Calculez le montant des produits commandés dont le libellé contient 'sapin'.
Calculez le nombre d’unités de produits commandés dont le libellé contient 'sapin'.
Quel est le produit dont la quantité en stock est la plus faible ?
Calculer le nombre de fois où chaque produit a été commandé.
Ajouter des données dans une table
Pour ajouter une ligne dans une table on utilise les mots clé INSERT INTO pour préciser la table
dans laquelle on souhaite effectuer une insertion et VALUES pour préciser les valeurs à ajouter pour
les différentes colonnes concernées.
Syntaxe générale :
INSERT INTO nom_table (col_1, ..., col_n)
VALUES (val_1, ...,val_n)
col_1, ..., col_n désignent ici les colonnes pour lesquelles nous allons fournir des valeurs (toutes sauf
éventuellement celles qui sont optionnelles ou auto-incrémentées) dans l'ordre dans lesquelles nous
souhaitons les fournir ce qui permet de s'abstraire de l'ordre déclaré au niveau du système de base
de données.
val_1, ..., val_n sont les valeurs correspondantes sachant que val_1 doit correspondre à la valeur que
l'on souhaite donner à la colonne col_1 et ainsi de suite.
Exemple :
INSERT INTO detail (NCOM, NPRO, QCOM)
VALUES ('30185', 'PA45', 12)
82
La requête ci-dessus permet d'ajouter les valeurs '30185' pour la colonne nommée NCOM, 'PA45'
pour la colonne nommée NPRO et 12 pour la commande nommée QCOM dans une table nommée
détail.
Remarques :
Toute colonne non spécifiée dans la liste des colonnes prend la valeur NULL, la valeur par défaut si
celle-ci a été déclarée comme propriété de la colonne, ou une valeur possible générée par le système
dans le cas d'une colonne auto-incrémentée.
Chaque valeur fournie (issue éventuellement d'un calcul) doit avoir même type que celui de la
colonne concernée.
De manière générale, les données ajoutées doivent respecter les contraintes d’intégrité (unicité,
intégrité référentielle, colonnes obligatoires) attachées à la table dans laquelle la nouvelle ligne est
insérée (cf. section 8.3).
8.5.3
Supprimer des données dans une table
Pour supprimer des lignes dans une table on utilise le mot clé DELETE FROM pour préciser la table
qui sera concernée et le mot clé WHERE pour préciser les lignes concernées c'est-à-dire celles qui
correspondront à la condition spécifiée.
Syntaxe générale :
DELETE FROM nom_table
WHERE condition
Ici l'usage du WHERE est analogue à celui vu précédemment pour l'extraction d'informations (cf.
section 8.5.1).
De même qu'après un ajout, après une suppression, la base de données doit être dans un état qui
respecte toutes les contraintes d’intégrité (unicité, intégrité référentielle, colonnes obligatoires)
auxquelles elle est soumise sans quoi l'opération sera refusée et une erreur sera retournée.
8.5.4 Modifier le contenu d'une table
Pour modifier des valeurs dans les lignes d’une table nous aurons recours au mot clé UPDATE pour
préciser la table concernée, SET pour préciser la liste des affections à réaliser ainsi qu'au mot clé
WHERE si les modifications ne concernent que les lignes qui correspondent à une certaine condition.
Syntaxe générale :
UPDATE nom_table
SET nom_colonne = nouvelle_valeur,
...
nom_colonne = nouvelle_valeur,
WHERE condition
La modification sera effectuée pour toutes les lignes qui vérifient la condition de sélection.
Les nouvelles valeurs peuvent résulter de calculs.
Exemple :
UPDATE produit
SET PRIX = PRIX * 1.05
WHERE LIBELLE like ’%SAPIN%’
Dans la requête ci-dessus, pour une table nommée produit la colonne nommée PRIX verra ses
valeurs augmentées de 5 % si dans la colonne nommée LIBELLE la valeur contient SAPIN.
83
Exercice 55 :
Pour chaque requête donnée ci-dessous expliquez ce qu’elle fait et trouvez la réponse attendue.
ATTENTION! Le contenu de la base de données sera modifié !
UPDATE produit
SET QSTOCK = QSTOCK - 10
WHERE NPRO = 'PH222'
UPDATE client
SET CAT = 'A1'
WHERE CAT IS NULL
INSERT INTO produit ( NPRO, LIBELLE, PRIX, QSTOCK)
VALUES ( 'PH122', 'PL HETRE 100 x20x2', '120', '500')
DELETE FROM detail
WHERE NCOM = '30188'
DELETE FROM commande
WHERE NCOM = '30188'
Exercice 56 :
En utilisant à nouveau l'application AgroPythia vérifiez vos réponses à l'Exercice 55. Pour éviter de
les retaper, celles-ci ont été retranscrites dans le fichier requetes_client_commande.sql. Vous
pourrez ainsi procéder par copier-coller.
84
Exercice 57 : Requêtes de mises à jour
Utilisez l'application AgroPythia pour écrire les requêtes SQL qui répondent aux questions suivantes
et copiez-les dans le fichier requetes_client_commande.sql.
1. Ajoutez un nouveau client, nommé 'FRANCK', qui habite à Lille, au 14 avenue du Reclus (son
numéro de client est 'W100' et son compte est 0.0).
2. Enregistrez une première commande du client 'FRANCK' : 10 unités du produit 'PL. HETRE
200x20x2' (le numéro de sa commande est 30189).
3. Mettez à jour le stock du produit 'PL. HETRE 200x20x2'.
4. Mettez à jour toutes les tables concernées pour enregistrer l’opération suivante : Le client
'FRANCK' achète aussi 25 unités du produit 'POINTE ACIER 60 (1K)' sur la même commande
30189.
5. Corrigez la quantité commandée du produit 'PA60' dans la commande '30185' : elle est de 10
unités.
Exercice 58 : Mises à jour et contraintes d'intégrité
Pour chaque question donnée ci-dessous trouvez la réponse en la justifiant :
1. Est-il possible d’ajouter un client ayant le même nom qu’un client déjà présent dans la base
de données ?
2. Est-il possible d’ajouter dans la base de données une commande ayant pour numéro de
commande '30179' (une commande existante), pour numéro de client 'C400' (un client
existant) et dont la date de commande serait le 04/01/2012 (une nouvelle date) ?
3. Est-il possible d’ajouter à la commande numéro '30188' le produit 'PS222' ? Et le produit
'PH222' ?
4. Est-il possible d’ajouter dans la base de données un produit dont le numéro est 'PH222' et le
libellé 'Planche' ?
5. Quelle est la liste des mises à jour à faire pour supprimer la commande '30179' ?
6. Est-il possible de supprimer n’importe quel enregistrement de la table detail ?
85
7. Est-il possible de supprimer n’importe quel enregistrement de la table commande ?
8. Est-il possible de supprimer n’importe quel enregistrement de la table produit ?
9. Est-il possible de supprimer n’importe quel enregistrement de la table client ?
8.5.5
Créer une base de données
Nous avons vu jusqu'à présent comment il est possible de sélectionner de l'information stockée dans
une base de données ou de la modifier grâce au langage SQL. Ce langage permet également d'agir
sur le schéma de la base de données en commençant par la création de la base elle-même.
Compte tenu de l'architecture simplifiée de SQLite, la création d'une base de donnée se résume à
fournir un nom de fichier par exemple client_commande.sqlite. L'extension peut être quelconque.
8.5.6
Créer / Supprimer/ Modifier la structure d'une table
Création
Pour créer une table nous aurons recours à la syntaxe suivante :
CREATE TABLE nom_de_la_table (
nom_de_la_premiere_colonne type,
nom_de_la_suivante type,
...
nom de la derniere type
)
La mise en page des instructions ici n'a pas d'influence sur leur signification et est réalisée
uniquement pour la lisibilité.
Il faut indiquer le nom de la nouvelle table, nom_de_la_table, ainsi que la description de ses
colonnes : pour chaque colonne il faut spécifier son nom et son type.
Sur les colonnes on peut ajouter le cas échéant les contraintes à considérer :
– pour définir une colonne obligatoire, il faut ajouter NOT NULL après sa définition ;
– pour définir une clé primaire, il faut ajouter PRIMARY KEY après sa définition ;
– pour définir une clé étrangère, il faut ajouter FOREIGN KEY (colonne) REFERENCES table_cible
(colonne_cible) après la liste des colonnes.
Par exemple la création de la table commande de notre exemple précédent se ferait par la requête
suivante :
86
CREATE TABLE commande (
NCOM INTEGER PRIMARY KEY,
NCLI TEXT NOT NULL,
Date TEXT NOT NULL,
FOREIGN KEY (NCLI) REFERENCES client(NCLI)
)
Cette opération produit une table vide (c’est-à-dire sans ligne).
Pour compléter cela, le mot clé AUTOINCREMENT est noté après la définition d'une colonne de type
entier pour laquelle on souhaite que le système attribue automatiquement des valeurs non encore
utilisées, ce qui s'avère particulièrement utile pour les clés primaires lorsque les numéros attribués
n'ont pas de sens particulier par rapport à l'entité décrite.
Le mot clé DEFAULT, quant à lui, sera utilisé pour préciser une valeur pour défaut pour une colonne.
Exemple :
CREATE TABLE nom_table (
ID INTEGER PRIMARY KEY AUTOINCREMENT,
NOM TEXT NOT NULL DEFAULT NO_Name
)
Suppression
Pour supprimer une table nous utiliserons la syntaxe suivante :
DROP TABLE nom_de_la_table
Remarque : Si cette table contenait des données, elles seront perdues.
Modification
La modification du schéma d’une base de données implique le plus souvent des modifications au
niveau des données elles-mêmes. Par exemple, l’ajout d’une colonne à une table contenant des
lignes est suivi de la modification de cette colonne pour chacune des lignes en indiquant NULL ou la
valeur par défaut si elle est spécifiée. Pour pouvoir être appliquées, ces opérations de modification
doivent respecter les contraintes d’intégrité.
Il en découle que :
– Pour ajouter une colonne, si la colonne est facultative, l’opération s’effectue sans contrainte.
Si elle est obligatoire, alors la table doit être vide ou la colonne doit être accompagnée d’une
valeur par défaut.
– Pour supprimer une colonne elle ne doit pas intervenir dans la composition d’une clé
(primaire ou étrangère). Si nécessaire, ces clés doivent d’abord être modifiées ou
supprimées.
– Pour ajouter une clé primaire, si la table n’est pas vide, les lignes doivent respecter la
contrainte d’unicité.
– Pour supprimer une clé primaire, elle ne doit pas être référencée par une clé étrangère.
Pour ajouter une clé étrangère, si la table n’est pas vide, les lignes doivent respecter la contrainte
référentielle.
87
À cause de toutes ces règles, la modification du schéma d’une base de données n’est pas une
opération aisée et elle doit être réalisée avec précaution et bien justifiée. Sqlite n'autorise pour sa
part que de renommer une table ou d'y ajouter des colonnes.
Pour plus de détails, vous pouvez vous reporter à la documentation de SQLite :
https://www.sqlite.org/.
88
Séance 7
9 Interaction avec des bases de données en Python
Python fournit les moyens d'utiliser les ressources de nombreux systèmes (MySQL, PostgreSQL,
SQLite, …). Pour ce cours nous interagirons avec une base de données SQLite. Les différentes
bibliothèques d’interaction avec des systèmes de base de données étant fondées sur la même API
(Application Programming Interface : ensemble de fonctions grâce auxquelles un logiciel offre des
services à d’autres logiciels), la transposition de ce qui sera vu à d’autres systèmes est en général très
simple.
Pour accéder aux fonctionnalités désirées, il suffit d'importer le module sqlite3 intégré à Python :
import sqlite3
(Le chiffre à la fin du nom est le numéro de la version actuelle du module d'interface. Il est possible
qu’il évolue avec le temps).
9.1 Se connecter à une base de données SQLite en Python
Une base de données Sqlite est matérialisée par un fichier dans lequel, sous un format maîtrisé par
SQLite, sont stockés tous les éléments de la base de données (schéma et contenu).
Pour pouvoir se connecter à une base de données il faudra donc connaître le nom du fichier sous
lequel elle a été sauvegardée et fournir cette information à notre programme par exemple en
utilisant une variable intermédiaire comme ci-dessous :
fichierDonnees = "E:/apprentis/bd_test.sqlite"
Vous devrez a priori préciser tout le chemin permettant d'accéder au fichier concerné.
Vous devez ensuite créer une variable de type connexion, à l'aide de la fonction connect().
Cet objet assurera l'interface entre votre programme et la base de données. L'opération est tout à
fait comparable à l'ouverture d'un simple fichier texte, l'instanciation de l'objet créant le fichier de
mémorisation au passage s'il n'existe pas déjà.
ma_connexion = sqlite3.connect(fichierDonnees)
Une fois l'objet connexion créé, il faut créer un objet dit curseur destiné à mémoriser
temporairement les données en cours de traitement et les opérations que vous effectuez sur elles,
avant leur transfert définitif dans la base de données. Cette technique permet donc d'annuler si
nécessaire une ou plusieurs opérations qui se seraient révélées inadéquates, et de revenir en arrière
dans le traitement, sans que la base de données n'en soit affectée.
89
mon_curseur = ma_connexion.cursor()
Grâce aux objets connexion et curseur créés, il est désormais possible de « dialoguer » avec la base
de données en effectuant des requêtes SQL.
Pour rappel, une base de données se compose toujours d'une ou plusieurs tables, qui contiendront
les enregistrements, ceux-ci comportant un certain nombre de champs (colonnes) de différents
types.
9.2 Interroger une base de données SQLite en Python
L'interrogation de la base s'effectue à l'aide de requêtes SQL (sous la forme de chaînes de caractères)
par l’intermédiaire de la méthode execute() du curseur.
Si nous souhaitons par exemple récupérer toutes les informations provenant d'une table qui
s'appellerait membres nous avons à écrire l'instruction suivante :
mon_curseur.execute("SELECT * FROM membres")
Cette requête demande la sélection d'un ensemble particulier d'enregistrements, qui devront être
transférés de la base de données au curseur.
Les enregistrements sélectionnés sont donc à présent dans le curseur. Si nous voulons les voir, nous
devons les en extraire. Cela peut être réalisé de deux façons qui tirent parti du fait que l'objetcurseur produit par Python est un itérateur, c'est-à-dire un dispositif générateur de séquences.
Vous pouvez parcourir directement la séquence qu'il produit, à l'aide d'une boucle for classique.
Vous obtenez une série de tuples (séquences analogues aux listes mais non modifiables et bordés
par des parenthèses).
Par exemple :
for un_tuple in mon_curseur:
print(un_tuple)
pourrait avoir comme résultat ce qui suit si la base de données contient bien les trois membres cités
ci-dessous :
(21, 'Dupont', 1.83)
(15, 'Blumâr', 1.57)
(18, 'Özémir', 1.69)
Vous pouvez également la recueillir dans une liste en vue d'un traitement ultérieur (à l'aide de la
fonction intégrée list()) :
mon_curseur.execute("SELECT * FROM membres")
liste_resultats = list(cur)
#[(21, 'Dupont', 1.83), (15, 'Blumâr', 1.57), (18, 'Özémir', 1.69)]
Vous pouvez également, d'une manière plus classique, faire appel à la méthode fetchall() du curseur,
laquelle renvoie elle aussi une liste de tuples :
mon_curseur.execute("SELECT * FROM membres")
liste_resultats = mon_curseur.fetchall()
#[(21, 'Dupont', 1.83), (15, 'Blumâr', 1.57), (18, 'Özémir', 1.69)]
90
9.3 Interrogation contextuelle
Dans la pratique, les données que l'on souhaite extraire de notre base de données dépendent le plus
souvent du contexte dans lequel on se trouve. Par exemple, nous souhaitons avoir les informations
sur un client en particulier qui vient de se connecter à notre application de commande en ligne.
Du point du vue du programme cela signifie que nos requêtes vont donc dépendre de la valeur de
variables ici en Python.
Vous devrez donc construire la chaîne de caractères contenant la requête SQL, en y incluant les
valeurs tirées de ces variables. Il est cependant fortement déconseillé de faire appel dans ce but aux
techniques ordinaires de formatage des chaînes, car cela peut ouvrir une faille de sécurité dans vos
programmes, en y autorisant les intrusions par la méthode de piratage connue sous le nom de SQL
injection. Il faut donc plutôt confier le formatage de vos requêtes au module d'interface lui-même. La
bonne technique est illustrée ci-après : la chaîne « squelette » utilise le point d'interrogation comme
balise de conversion, et le formatage proprement dit est pris en charge par la méthode execute() du
curseur :
nom_client = "Durand"
mon_curseur.execute("SELECT * from clients WHERE nom = ?", nom_client)
9.4 Se déconnecter d'une base de données SQLite en Python
Une fois les échanges souhaités avec la base de données réalisés, le curseur et la connexion doivent
être refermés :
mon_curseur.close()
ma_connexion.close()
Exercice 59 : Les Simpsons
On donne la base de données simpsons.sqlite qui contient pour le moment une table nommée
personnages ayant trois colonnes nommée ID, Prenom, et Nom.
1. Écrivez un script nommé simpsons.py permettant de se connecter à cette base de données.
2. Ajoutez à votre script une fonction affiche_noms permettant d'afficher tous les noms
présents dans la base. Complétez votre programme principal pour tester votre fonction.
3. Ajoutez à votre script une fonction affiche_prenoms qui, étant donné un nom, permet
d'afficher les prénoms qui lui sont associés dans la base de donnée. Complétez votre
programme pour tester votre fonction avec un nom choisi par l'utilisateur. Pensez à vérifier
que l'utilisateur a bien fourni un nom contenu dans la base de données.
91
Exercice 60 : Locations de bateaux
Sur de nombreux canaux français, la navigation commerciale a laissé la place à la navigation de
plaisance. Ainsi la société Starboat s’est fait une réputation dans la location de pénichettes aux
touristes. Pour améliorer sa productivité, elle a besoin d’un système d’information afin d’équiper
chacun de ses centres de location d’un logiciel de gestion adapté à leurs activités.
Le schéma de base de données retenu pour cela est le suivant :
Figure 22 : Schéma de la base de données Starboat
Le système d’information conçu pour la société Starboat doit pouvoir fournir
– la liste de tous les bateaux en cours de location ;
– la liste des bateaux accompagnés des informations correspondant à leur modèle et classés
par modèle ;
– la liste de tous les bateaux de type Flying Bridge ;
– le nom du dernier bateau révisé ;
– la liste des bateaux qui ont subi un dommage en cours de location ;
– la liste des bateaux disponibles à la location.
Écrivez et testez les fonctions nécessaires pour répondre aux attentes précédentes. Pour la deuxième
fonctionnalité, vous devrez fournir un fichier contenant les informations désirées avec un bateau par
ligne et pour chaque ligne des tabulations entre les différentes valeurs souhaitées. Pour les autres
fonctionnalités uniquement un affichage à l'écran est attendu.
92
9.5 Insertions et suppressions
Lorsque l'on souhaite rajouter ou modifier de l'information dans une base de données depuis un
programme Python, cela se passe de manière analogue à de l'interrogation contextuelle puisqu'à
nouveau les données à enregistrer se présenteront dans des variables.
Il faudra donc de la même manière concevoir les requêtes adaptées et utiliser le formatage présenté
ci-dessus.
Voici un exemple :
data =[(17,"Durand",1.74),(22,"Berger",1.71),(20,"Weber",1.65)]
for tu in data:
mon_curseur.execute("INSERT INTO membres(age,nom,taille) VALUES(?,?,?)", tu)
ma_connexion.commit()
Dans cet exemple, la chaîne de requête comporte 3 points d'interrogation, qui sont nos balises. Elles
seront remplacées par les 3 éléments du tuple tu à chaque itération de la boucle, le module
d'interface avec SQLite se chargeant de traiter chaque variable correctement en fonction de son
type.
Pour modifier un ou plusieurs enregistrements, exécutez une requête du type :
mon_curseur.execute("UPDATE membres SET nom ='Gerart' WHERE nom='Ricard'")
ma_connexion.commit()
Pour supprimer un ou plusieurs enregistrements, utilisez une requête telle que :
mon_curseur.execute("DELETE FROM membres WHERE nom='Gerart'")
ma_connexion.commit()
Attention :
Notez la présence de l'instruction commit :
Toutes les modifications apportées au curseur se passent en mémoire vive, et de ce fait rien n'est
enregistré définitivement tant que vous n'exécutez pas l'instruction ma_connexion.commit().
Si vous fermez prématurément la connexion avec l'instruction ma_connexion.close()les
modifications seront perdues.
Si l'on souhaite annuler toutes les modifications apportées depuis le commit() précédent, il faudra
avoir recours à l'instruction : ma_connexion.rollback()
18-A-6. Recherches sélectives dans une base de données▲
93
9.6 Création du schéma d'une base de données depuis un programme
Python
La création d’une nouvelle table dans notre base de données se fait par exemple par l’instruction cidessous :
mon_curseur.execute("CREATE TABLE membres (age INTEGER, nom TEXT, taille REAL)")
Ici nous avons créé une table nommée membres contenant trois champs : age de type entier, nom de
type chaîne de caractères et taille de type réel.
94
Séances 8 & 9
10 Projet
Les deux dernières séances de ce module seront consacrées à la réalisation d'un projet en binôme
dont l'énoncé et les consignes vous seront communiqués en temps utiles.
95
Téléchargement