From bf654008771a60f6fb5cf42b3052edf9c393018a Mon Sep 17 00:00:00 2001 From: <> Date: Thu, 9 Nov 2023 09:59:29 +0000 Subject: [PATCH] Deployed 70311db with MkDocs version: 1.5.3 --- .../2.1_Listes/cours/index.html | 77 +++++++++- search/search_index.json | 2 +- sitemap.xml | 138 +++++++++--------- sitemap.xml.gz | Bin 1025 -> 1025 bytes 4 files changed, 140 insertions(+), 77 deletions(-) diff --git a/T2_Representation_des_donnees/2.1_Listes/cours/index.html b/T2_Representation_des_donnees/2.1_Listes/cours/index.html index 841af82b..44efd1c3 100644 --- a/T2_Representation_des_donnees/2.1_Listes/cours/index.html +++ b/T2_Representation_des_donnees/2.1_Listes/cours/index.html @@ -4251,8 +4251,38 @@
1 +2 +3 +4 +5 +6 |
|
1 +2 +3 +4 +5 +6 +7 |
|
Inconvénient : on part du principe que ce nombre existe vraiment. Si on ne le trouve pas, on aura une erreur...
+lst = [2428970, 1518306, 4971405, 1690994, 7918102, 4030834, 8830131, 7514856, 7903128, 6307569, 6624056, 5260490, 6447835, 4598783, 9108626, 5045240, 4128269, 4460134, 2497873, 5076659, 8104003, 7604887, 7451976, 4136924, 5691945, 8726293, 7855592, 3562473, 8849129, 6488474, 5303587, 2606124, 5484044, 4559758, 7592232, 2211406, 9974334, 7988936, 7582946, 7668748, 1799997, 3837917, 3196209, 7064342, 2543765, 1182013, 7253381, 1153735, 1037391, 4375946, 4445821, 5965587, 6001887, 4162629, 5235783, 8716582, 4901175, 5445422, 1120005, 8332321, 7075046, 2194175, 5557300, 2887907, 5103214, 2520744, 5104399, 2065665, 3035703, 7890213, 1758301, 3407982, 1355453, 4896338, 7979392, 9671602, 9690721, 7423779, 7423780, 3080825, 6785783, 3836837, 7310931, 1857470, 3492507, 2823231, 1492310, 1911148, 9620515, 5564910, 7009452, 7464745, 9608747, 7267383, 6939140, 6556578, 3592267, 8135497, 4881660, 5346884, 6859150]
[6, 2, 4, 5, 3]
). Pouvez-vous les trouver ?
+
+1 +2 +3 +4 +5 |
|
Construire une liste contenant tous les nombres inférieurs à 100 qui sont divisibles par 7.
1 +2 +3 +4 |
|
On considère la liste temp = [4, -5, 8, 10, -1, -2, 7, 13]
.
Construire la liste temp_pos
qui ne contient que les éléments positifs de temp
.
1 +2 +3 +4 +5 +6 |
|
Anciens th\u00e8mes trait\u00e9s
if
if
while
for ... in ...
for ... in ...
Consid\u00e9rons la phrase \u00abnous allons stocker le prix du spectacle dans une variable a
, qui vaudra donc au d\u00e9part 32.\u00bb
Il y a plusieurs commentaires \u00e0 faire sur une telle annonce :
a
est particuli\u00e8rement mal choisi, voir D. Bonnes pratiques de nommage)La phrase pr\u00e9c\u00e9dente donnera donc lieu \u00e0 la ligne Python suivante :
>>> a = 32\n
Attention
Le symbole =
ici utilis\u00e9 n'a rien \u00e0 voir avec le symbole = utilis\u00e9 en math\u00e9matique. On dit qu'on a affect\u00e9 \u00e0 a
la valeur 32, et il faut se repr\u00e9senter mentalement cette action par l'\u00e9criture a \u2190 32
.
Comparaison de la syntaxe dans diff\u00e9rents langages
PythonCPHPJavaJavascriptRustGoa = 32\n
int a = 32;\n
$a = 32;\n
int a = 32;\n
var a = 32;\n
let a = 32;\n
a := 32\n
Une fois la valeur 32 stock\u00e9e dans la variable a
, on peut alors utiliser cette variable :
>>> a\n32\n>>> a + 5\n37\n>>> b\nTraceback (most recent call last):\n File \"<pyshell>\", line 1, in <module>\nNameError: name 'b' is not defined\n
Remarquez bien l'erreur lorsqu'on a fait appel \u00e0 une variable b
qui n'avait jamais \u00e9t\u00e9 d\u00e9finie, comme le dit explicitement le message NameError: name 'b' is not defined
En premi\u00e8re intention, il est possible d'expliquer le fonctionnement interne de l'affectation des variables par la m\u00e9taphore des tiroirs :
\u00c9crire l'instruction :
>>> a = 2\n
va provoquer chez l'ordinateur le comportement suivant :
a
? a
.Cette explication est suffisante pour aborder la notion de variable : c'est un mot (ou une lettre) qui va d\u00e9signer une valeur.
Partie difficile (optionnelle)La m\u00e9taphore du tiroir est malheureusement un peu trop simplificatrice.
"},{"location":"T1_Demarrer_en_Python/1.1_Variables/cours/#b2-une-realite-bien-plus-complexe","title":"B.2 Une r\u00e9alit\u00e9 bien plus complexe...","text":""},{"location":"T1_Demarrer_en_Python/1.1_Variables/cours/#b21-la-commande-id-ladresse-du-tiroir","title":"B.2.1 La commandeid()
: l'adresse du tiroir ?","text":"Python poss\u00e8de une fonction qui renvoie l'adresse m\u00e9moire de la variable donn\u00e9e en argument.
>>> b = 7\n>>> id(b)\n9788800\n
Faites le test avec votre propre IDE Python (vous n'obtiendrez pas forc\u00e9ment la m\u00eame valeur d'adresse m\u00e9moire)
"},{"location":"T1_Demarrer_en_Python/1.1_Variables/cours/#b22-cela-se-complique","title":"B.2.2 Cela se complique.","text":"Sans refermer notre IDE, \u00e9crasons la valeur de b
avec une nouvelle valeur :
>>> b = 12\n
et redemandons l'adresse de b
: >>> id(b)\n9788960\n
Tr\u00e8s mauvaise nouvelle : l'adresse de la variable b
a chang\u00e9. Ceci invalide notre m\u00e9taphore du \u00abtiroir\u00bb, une place unique qui serait r\u00e9serv\u00e9e pour y stocker les valeurs successives d'une variable.
La modification de la valeur de b
ne s'est pas faite \u00aben place\u00bb, la variable b
s'est d\u00e9plac\u00e9e : que s'est-il donc pass\u00e9 ?
L'affectation
>>> b = 9\n
ne provoque pas la r\u00e9servation d\u00e9finitive d'un espace-m\u00e9moire pour la variable b
, mais la cr\u00e9ation d'un lien vers un espace-m\u00e9moire qui contient la valeur 9. Ce lien consiste en l'adresse-m\u00e9moire de cette valeur 9. Cette adresse-m\u00e9moire vaut (sur ma configuration personnelle) 9788864
.
>>> id(b)\n9788864\n
Comme le pr\u00e9sente le ruban ci-dessus, Python pr\u00e9-positionne les entiers (de -5 \u00e0 256) sur des petites adresses-m\u00e9moires, car il consid\u00e8re que ces entiers servent souvent, et doivent donc \u00eatre rapidement accessibles.
Si on cr\u00e9\u00e9 une nouvelle variable tokyo
aussi \u00e9gale \u00e0 9, elle va aussi pointer vers la m\u00eame adresse-m\u00e9moire :
>>> tokyo = 9\n>>> id(tokyo)\n9788864\n
Les variables tokyo
et b
renvoient vers la m\u00eame adresse-m\u00e9moire. Affectons maintenant \u00e0 tokyo
la valeur 2020 et observons son adresse-m\u00e9moire :
>>> tokyo = 2020\n>>> id(tokyo)\n139762979309936\n
L'adresse-m\u00e9moire est (bien) plus grande : elle a \u00e9t\u00e9 choisie sur le moment par Python pour y stocker 2020 (car 2020 > 256).
De mani\u00e8re plus surprenante, si on cr\u00e9\u00e9 une nouvelle variable jo
qui vaut aussi 2020, Python va ouvrir une autre adresse-m\u00e9moire pour y stocker 2020, alors qu'il l'a d\u00e9j\u00e0 stock\u00e9e ailleurs :
>>> jo = 2020\n>>> id(jo)\n139762979310064\n
En r\u00e9sum\u00e9, une variable n'est pas le nom d'un tiroir mais plut\u00f4t le nom d'une fl\u00e8che qui pointe vers un espace-m\u00e9moire de l'ordinateur. - La fl\u00e8che peut pointer vers un nouvel espace-m\u00e9moire sans que le nom de la variable change. - Deux variables peuvent pointer vers le m\u00eame espace-m\u00e9moire.
"},{"location":"T1_Demarrer_en_Python/1.1_Variables/cours/#b3-une-histoire-en-2-temps-evaluation-affectation","title":"B.3 Une histoire en 2 temps : \u00e9valuation, affectation","text":"Observons l'instruction
>>> a = 2 + 3\n
"},{"location":"T1_Demarrer_en_Python/1.1_Variables/cours/#b31-etape-1-levaluation","title":"B.3.1 \u00c9tape 1 : l'\u00e9valuation","text":"Python va prendre la partie \u00e0 droite du signe \u00e9gal et va l'\u00e9valuer, ce qui signifie qu'il va essayer de lui donner une valeur. Dans nos exemples, cette valeur sera num\u00e9rique, mais elle peut \u00eatre d'un autre type (voir plus loin)
Ici, Python effectue le calcul 2 + 3 et l'\u00e9value \u00e0 la valeur 5.
"},{"location":"T1_Demarrer_en_Python/1.1_Variables/cours/#b32-etape-2-laffectation","title":"B.3.2 \u00c9tape 2 : l'affectation","text":"Une fois \u00e9valu\u00e9e l'expression \u00e0 droite du signe =, il ne reste plus qu'\u00e0 l'affecter \u00e0 la variable (d\u00e9j\u00e0 existante ou pas) situ\u00e9e \u00e0 gauche du signe =.
Comme expliqu\u00e9 pr\u00e9c\u00e9demment, un \u00ablien\u00bb est fait entre le nom de la variable et l'adresse-m\u00e9moire qui contient la valeur \u00e9valu\u00e9e. a
sera donc li\u00e9 \u00e0 la valeur 5. Plus simplement, on dira que \u00aba
vaut 5\u00bb
\u00abIncr\u00e9menter\u00bb une variable signifie l'augmenter.
Imaginons une variable appel\u00e9e compteur
. Au d\u00e9marrage de notre programme, elle est initialis\u00e9e \u00e0 la valeur 0.
>>> compteur = 0\n
Consid\u00e9rons qu'\u00e0 un moment du programme, cette variable doit \u00eatre modifi\u00e9e, par exemple en lui ajoutant 1.
En Python, cela s'\u00e9crira :
>>> compteur = compteur + 1\n
Observ\u00e9e avec des yeux de math\u00e9maticien, la pr\u00e9c\u00e9dente instruction est une horreur.
Vue avec des yeux d'informaticien, voil\u00e0 comment est interpr\u00e9t\u00e9e la commande
>>> compteur = compteur + 1\n
compteur + 1
.compteur
. Si celle-ci n'existe pas, un message d'erreur est renvoy\u00e9.compteur
.compteur
avec la valeur obtenue au 3. \u00c0 la fin de ces op\u00e9rations, la variable compteur
a bien augment\u00e9 de 1.
Cette proc\u00e9dure d'incr\u00e9mentation est tr\u00e8s tr\u00e8s classique, il faut la ma\u00eetriser parfaitement !
Syntaxe classique et syntaxe Pythonesque
L'incr\u00e9mentation d'une variable compteur
s'\u00e9crira donc en Python :
>>> compteur = compteur + 1\n
Mais il existe aussi une syntaxe particuli\u00e8re, un peu plus courte : >>> compteur += 1\n
Cette syntaxe peut se ranger dans la cat\u00e9gorie des sucres syntaxiques : c'est bien de la conna\u00eetre, c'est amusant de s'en servir, mais son utilisation n'est en rien obligatoire et peut avoir un effet n\u00e9faste, celui d'oublier r\u00e9ellement ce qu'il se passe derri\u00e8re. Exercice 1
\u00c9nonc\u00e9Correction\u00c9crire le code \u00abclassique\u00bb et le code \u00abPythonesque\u00bb pour l'instruction suivante :
On initialise une variable score
\u00e0 100 et on l'augmente de 15.
>>> score = 100\n>>> score = score + 15\n
ou encore >>> score = 100\n>>> score += 15\n
Exercice 2
\u00c9nonc\u00e9Correction\u00c9crire le code \u00abclassique\u00bb et le code \u00abPythonesque\u00bb pour l'instruction suivante :
On initialise une variable cellule
\u00e0 1 et on la multiplie par 2.
>>> cellule = 1\n>>> cellule = cellule * 2\n
ou bien >>> cellule = 1\n>>> cellule *= 2\n
Exercice 3
\u00c9nonc\u00e9Correction\u00c9crire le code \u00abclassique\u00bb et le code \u00abPythonesque\u00bb pour l'instruction suivante.
On initialise une variable capital
\u00e0 1000 et on lui enl\u00e8ve 5%.
>>> capital = 1000\n>>> capital = capital - capital * 5/100\n
ou bien >>> capital = 1000\n>>> capital *= 0.95\n
"},{"location":"T1_Demarrer_en_Python/1.1_Variables/cours/#b33-lechange-de-variables","title":"B.3.3 L'\u00e9change de variables","text":"Apr\u00e8s l'incr\u00e9mentation, une autre technique de base reviendra fr\u00e9quemment dans nos codes : l'\u00e9change de variables.
Imaginons les variables suivantes :
>>> a = 3\n>>> b = 5\n
Le but est d'\u00e9changer les valeurs de a
et de b
. \u25b8 M\u00e9thode na\u00efve
>>> a = b\n>>> b = a\n
Que valent a
et b
maintenant ?
Malheureusement :
>>> a\n5\n>>> b\n5\n>\n
La variable a
a \u00e9t\u00e9 \u00e9cras\u00e9e d\u00e8s qu'on lui a donn\u00e9 la valeur de la variable b
.
Comment la pr\u00e9server ?
La situation est similaire au probl\u00e8me suivant : comment \u00e9changer le contenu de ces deux verres ?
La m\u00e9thode est \u00e9vidente : il nous faut un troisi\u00e8me verre.
Nous allons faire de m\u00eame pour nos variables. Nous allons utiliser une variable temporaire (on parle aussi de variable tampon) pour conserver la m\u00e9moire de la valeur de a
(par exemple) avant que celle-ci ne se fasse \u00e9craser :
>>> a = 3\n>>> b = 5\n>>> temp = a\n>>> a = b\n>>> b = temp\n
Vous pouvez v\u00e9rifier maintenant que les valeurs de a
et de b
ont bien \u00e9t\u00e9 \u00e9chang\u00e9es.
Syntaxe classique et syntaxe Pythonesque
L'\u00e9change de deux variables a
et de b
s'\u00e9crit donc :
>>> temp = a\n>>> a = b\n>>> b = temp\n
Mais il existe aussi une syntaxe particuli\u00e8re \u00e0 Python, bien plus courte : >>> a, b = b, a\n
C'est de nouveau un sucre syntaxique. Cette syntaxe nous dispense de cr\u00e9er nous-m\u00eame une troisi\u00e8me variable. Mais pas de miracle : en interne, Python cr\u00e9e lui-m\u00eame cette variable temporaire. La simultan\u00e9it\u00e9 n'existe pas en informatique. Exercice 4
\u00c9nonc\u00e9CorrectionUne petite erreur s'est gliss\u00e9e \u00e0 Poudlard :
>>> maison_Harry = \"Serpentard\"\n>>> maison_Malfoy = \"Gryffondor\"\n
Corriger cette erreur, de deux mani\u00e8res diff\u00e9rentes. >>> t = maison_Harry\n>>> maison_Harry = maison_Malfoy\n>>> maison_Malfoy = t\n
ou plus rapidement : >>> maison_Harry, maison_Malfoy = maison_Malfoy, maison_Harry\n
"},{"location":"T1_Demarrer_en_Python/1.1_Variables/cours/#c-differents-types-de-variables","title":"C. Diff\u00e9rents types de variables","text":"Pour l'instant, les variables que nous avons manipul\u00e9es contiennent toutes des nombres entiers.
Sauf les maisons de Poudlard, qui sont des mots cha\u00eenes de caract\u00e8res.
Pour diff\u00e9rencier la nature de ce que peut contenir une variable, on parle alors de type de variable.
En voici quelques uns, que nous d\u00e9couvrirons au fil de l'ann\u00e9e :
Types de base
Voici les types Python les plus fr\u00e9quemment utilis\u00e9s cette ann\u00e9e:
Type Python Traduction Exempleint
entier 42
float
flottant (d\u00e9cimal) 3.1416
str
cha\u00eene de caract\u00e8res (string) \"NSI\"
bool
bool\u00e9en (True ou False) True
tuple
p-uplet (255, 127, 0)
list
liste [0, 1, 2, 3, 4, 5]
dict
dictionnaire {'Homer':43, 'Marge':41, 'Bart':12, 'Lisa':10, 'Maggie':4}
function
fonction print
Comment conna\u00eetre le type d'une variable ? Il suffit dans la console d'utiliser la fonction type
.
>>> a = 1\n>>> type(a)\n<class 'int'>\n
"},{"location":"T1_Demarrer_en_Python/1.1_Variables/cours/#c1-python-et-le-typage-dynamique","title":"C.1 Python et le typage dynamique","text":"Jusqu'\u00e0 pr\u00e9sent, nous ne nous sommes pas occup\u00e9s de pr\u00e9ciser \u00e0 Python le type de notre variable.
a = 3\n
Mais dans certains langages, c'est obligatoire. En C par exemple, il faut \u00e9crire :
int a = 3;\n
Cela signifie (pour le langage C) que notre variable a
n'aura pas le droit de contenir autre chose qu'un nombre entier. Si on \u00e9crit ensuite
a = \"test\";\n
Le compilateur C renverra une erreur : on ne peut pas stocker une cha\u00eene de caract\u00e8res dans une variable qu'on a cr\u00e9\u00e9e comme \u00e9tant de type entier.
Et en Python ?
>>> a = 3\n>>> type(a)\n<class 'int'>\n>>> a = \"test\"\n>>> type(a)\n<class 'str'>\n
Python a chang\u00e9 tout seul le type de notre variable, sans intervention. On parle de typage dynamique.
"},{"location":"T1_Demarrer_en_Python/1.1_Variables/cours/#d-bonnes-pratiques-de-nommage","title":"D. Bonnes pratiques de nommage","text":""},{"location":"T1_Demarrer_en_Python/1.1_Variables/cours/#d1-ce-qui-est-autorise-et-ce-qui-ne-lest-pas","title":"D.1 Ce qui est autoris\u00e9 et ce qui ne l'est pas","text":"Pour nommer correctement une variable, il existe des r\u00e8gles \u00e0 respecter.
Les r\u00e8gles
le nom de la variable peut contenir les caract\u00e8res suivants :
le nom de la variable ne doit pas commencer par un chiffre
andas assert break class continue def del elif else except False finally for from global if import in is lambda None not or pass raise return True try while with yield
"},{"location":"T1_Demarrer_en_Python/1.1_Variables/cours/#d2-du-sens-du-sens-du-sens","title":"D.2 Du sens, du sens, du sens","text":"Hormis pour les indices (de boucles, de tableaux...) un nom de variable (dans un programme destin\u00e9 \u00e0 \u00eatre lu, par vous ou quelqu'un d'autre) doit imp\u00e9rativement avoir du sens :
# PAS BIEN\nif d == 1:\n cep += vm\n\n# BIEN\nif date == 1:\n compte_epargne += versement_mensuel\n
R\u00e8gle d'or
On ne donne jamais un nom de variable au hasard, on le choisit pour qu'il soit explicite.
Oui mais pour donner du sens, il faut souvent plusieurs mots... La longueur du nom de la variable (\u00abc'est trop long \u00e0 taper\u00bb) n'est plus un probl\u00e8me depuis que la grande majorit\u00e9 des IDE propose la compl\u00e9tion automatique. Mais comment former ces longs mots ?
"},{"location":"T1_Demarrer_en_Python/1.1_Variables/cours/#d3-syntaxe-des-noms-a-rallonge","title":"D.3 Syntaxe des noms \u00e0 rallonge","text":"Comment accoler des mots
snake_case
: les mots sont s\u00e9par\u00e9s par des underscores. Conseill\u00e9 en Python.camelCase
: les mots sont s\u00e9par\u00e9s par des majuscules mais la 1\u00e8re lettre est minuscule. Conseill\u00e9 en Javascript.PascalCase
: les mots sont s\u00e9par\u00e9s par des majuscules et la 1\u00e8re lettre est majuscule. Conseill\u00e9 en C.kebab-case
: les mots sont s\u00e9par\u00e9s par des tirets courts. Conseill\u00e9 en HTML - CSS. Sans surprise, en Python, nous utiliserons donc le snake_case
.
for ... in ...
","text":""},{"location":"T1_Demarrer_en_Python/1.2_Boucle_for/cours/#1-les-enumerables","title":"1. Les \u00e9num\u00e9rables","text":"En math\u00e9matiques, on dit qu'un ensemble est d\u00e9nombrable lorsqu'on peut associer \u00e0 chaque \u00e9l\u00e9ment de l'ensemble un nombre (traditionnellement 1, 2, 3 ...)
En informatique, il existe un concept similaire qui va d\u00e9signer les objets que l'on peut \u00e9num\u00e9rer, c'est-\u00e0-dire les d\u00e9composer en une succession ordonn\u00e9e d'\u00e9l\u00e9ments. On les appelle les \u00e9num\u00e9rables ou les it\u00e9rables (Python utilise le mot anglais iterable
).
\"NSI\"
(qui est de type String
) est \u00e9num\u00e9rable : on peut la d\u00e9composer en N
, S
, I
.[4, 3, 17]
(qui est de type List
) est \u00e9num\u00e9rable : on peut la d\u00e9composer en 4
, 3
, 17
.5
(qui est de type Int
) n'est PAS \u00e9num\u00e9rable : on ne peut pas la d\u00e9composer. for ... in ...
","text":""},{"location":"T1_Demarrer_en_Python/1.2_Boucle_for/cours/#21-iterer-sur-une-chaine-de-caracteres","title":"2.1 It\u00e9rer sur une cha\u00eene de caract\u00e8res","text":"La principale caract\u00e9ristique d'un ordinateur est d'exceller dans les op\u00e9rations r\u00e9p\u00e9titives.
(je vous laisse retrouver la citation de G\u00e9rard Berry, professeur au Coll\u00e8ge de France, commen\u00e7ant par \u00abl'ordinateur est...\u00bb)
Il existe donc une instruction permettant de faire une (ou plusieurs) action(s) \u00e0 chaque it\u00e9ration sur un \u00e9l\u00e9ment \u00e9num\u00e9rable.
Exemple fondateur n\u00b01
Le programme suivant :
for k in 'NSI':\n print(k)\n
va donner ceci : N\nS\nI\n
Analyse gr\u00e2ce \u00e0 PythonTutor
\u00c9tudions, gr\u00e2ce \u00e0 PythonTutor, le d\u00e9tail de cette ex\u00e9cution.
Cliquez sur Next et observez bien l'\u00e9volution de la variable k
.
La variable k
prend donc successivement toutes les lettre de la cha\u00eene de caract\u00e8re \"NSI\"
.
Pour chaque valeur de k
, la ou les instruction(s) situ\u00e9es de mani\u00e8re indent\u00e9e sous la ligne du for
seront ex\u00e9cut\u00e9es.
Ici, il y a simplement un print(k)
, donc chaque lettre de \"NSI\"
s'affiche l'une apr\u00e8s l'autre.
Exercice 1
\u00c9nonc\u00e9CorrectionQue donne le script suivant ?
for m in 'NASA':\n print(\"bonjour\")\n
bonjour\nbonjour\nbonjour\nbonjour\n
Dans cet exercice, la variable de boucle m
est muette : elle n'appara\u00eet dans les instructions indent\u00e9es sous le for
.
La variable m
prend successivement les valeurs 'N
, 'A'
, 'S'
et 'A'
, mais on ne le voit pas.
Comment \u00e9viter les erreurs classiques
Quand vous \u00e9crivez une boucle for ... in ...
, veillez bien \u00e0 :
for
par les deux points :
for
les instructions qui doivent \u00eatre r\u00e9p\u00e9t\u00e9es. Si l'indentation ne s'est pas faite automatiquement apr\u00e8s appui sur la touche Entr\u00e9e
, c'est que vous avez oubli\u00e9 les :
. Exemple fondateur n\u00b02
Le programme suivant :
for jour in [\"lundi\", \"mardi\", \"mercredi\", \"jeudi\", \"vendredi\"]:\n print(\"je vais au lyc\u00e9e le\", jour)\n
va donner ceci : je vais au lyc\u00e9e le lundi\nje vais au lyc\u00e9e le mardi\nje vais au lyc\u00e9e le mercredi\nje vais au lyc\u00e9e le jeudi\nje vais au lyc\u00e9e le vendredi\n
Analyse gr\u00e2ce \u00e0 PythonTutor
Attention: tr\u00e8s souvent, l'objet \u00e9num\u00e9rable que la boucle va parcourir aura \u00e9t\u00e9 au pr\u00e9alable stock\u00e9 dans une variable :
Exemple fondateur n\u00b03
Le programme pr\u00e9c\u00e9dent est \u00e9quivalent \u00e0 :
semaine = [\"lundi\", \"mardi\", \"mercredi\", \"jeudi\", \"vendredi\"]\nfor jour in semaine:\n print(\"je vais au lyc\u00e9e le\", jour)\n
Notez l'importance d'avoir choisi des noms de variables explicites : ils aident grandement \u00e0 la lisibilit\u00e9 du code.
Trailer : Dans le cours sp\u00e9cifique sur les listes, nous verrons une toute autre mani\u00e8re de parcourir une liste.
"},{"location":"T1_Demarrer_en_Python/1.2_Boucle_for/cours/#3-comment-repeter-n-fois-la-meme-action","title":"3. Comment r\u00e9p\u00e9tern
fois la m\u00eame action ?","text":"Scratch dispose du (tr\u00e8s pratique) bloc suivant :
Comment effectuer la m\u00eame chose en Python ?
Comment r\u00e9p\u00e9ter 10 fois la phrase \"We're up all night to get lucky\"
?
Nous pourrions nous en sortir par
for k in \"blablablab\": #(1) \n print(\"We're up all night to get lucky\")\n
mais il doit clairement y avoir mieux...
Il y a mieux !
L'ensemble range
Le programme suivant :
for i in range(5):\n print(\"We're up all night to get lucky\")\n
va donner ceci : We're up all night to get lucky\nWe're up all night to get lucky\nWe're up all night to get lucky\nWe're up all night to get lucky\nWe're up all night to get lucky\n
L\u00e0 encore, le i
est une variable muette.
Le _
comme variable muette
Lorsque la variable de boucle est muette et ne sert qu'\u00e0 effectuer \\(n\\) fois la m\u00eame action, on utilise souvent le caract\u00e8re _
(appel\u00e9 underscore)comme variable de boucle.
Il faut le comprendre comme un avertissement au lecteur du code : \u00abcette boucle ne sert qu'\u00e0 faire \\(n\\) fois la m\u00eame chose\u00bb
for _ in range(5):\n print(\"Tout \u00e7a est tr\u00e8s r\u00e9p\u00e9titif\")\n
"},{"location":"T1_Demarrer_en_Python/1.2_Boucle_for/cours/#4-tout-sur-le-range","title":"4. Tout sur le range
.","text":""},{"location":"T1_Demarrer_en_Python/1.2_Boucle_for/cours/#41-retour-sur-lexemple-precedent","title":"4.1 Retour sur l'exemple pr\u00e9c\u00e9dent.","text":"Si nous rendions la variable i
moins muette ?
for i in range(5):\n print(i, \"We're up all night to get lucky\")\n
va donner ceci : 0 We're up all night to get lucky\n1 We're up all night to get lucky\n2 We're up all night to get lucky\n3 We're up all night to get lucky\n4 We're up all night to get lucky\n
i
prend donc successivement toutes les valeurs enti\u00e8res entre 0 et 4. Il y en a bien 5."},{"location":"T1_Demarrer_en_Python/1.2_Boucle_for/cours/#42-utilisation-minimale-de-lobjet-range","title":"4.2 Utilisation minimale de l'objet range()
","text":"Syntaxe minimale de range()
Le programme suivant :
for k in range(4):\n print(k)\n
va donner ceci : 0\n1\n2\n3\n
Interpr\u00e9tation : faire parcourir \u00e0 une variable k
l'ensemble range(n)
va faire prendre \u00e0 k
les valeurs 0, 1, 2, ..., n-1. "},{"location":"T1_Demarrer_en_Python/1.2_Boucle_for/cours/#43-utilisation-avancee-de-lobjet-range","title":"4.3 Utilisation avanc\u00e9e de l'objet range()
","text":"Syntaxe compl\u00e8te de range()
Le programme suivant :
for k in range(5, 15, 2):\n print(k)\n
va donner ceci : 5\n7\n9\n11\n13\n
Interpr\u00e9tation : faire parcourir \u00e0 k
l'ensemble range(start, stop, step)
fait : k
\u00e0 la valeur start
,k
de step
en step
tant que k
est strictement inf\u00e9rieur \u00e0 stop
.Remarques :
step
est omis, il vaut 1 par d\u00e9faut.range(5)
n'est pas \u00abtechniquement\u00bb \u00e9gal \u00e0 la liste [0, 1, 2, 3, 4]
, car ce n'est pas un objet de type List
:>>> type(range(5))\n<class 'range'>\n
Si n\u00e9cessaire, on peut le convertir en liste : >>> list(range(5))\n[0, 1, 2, 3, 4]\n
Il faut donc garder en t\u00eate que l'objet renvoy\u00e9 par range()
est un it\u00e9rable assimilable \u00e0 une liste de nombres.
Exercice 2
Faire afficher les s\u00e9ries de nombres suivantes.\n\nOn utilisera la syntaxe ```print(k, end = ' ')``` ) pour afficher les nombres horizontalement.\n\nA. ```0 1 2 3 4 5``` \n??? success \"Correction\"\n ```python linenums='1'\n for k in range(6):\n print(k, end = ' ')\n ```\nB. ```10 11 12 13 14 15 ``` \n??? success \"Correction\"\n ```python linenums='1'\n for k in range(10,16):\n print(k, end = ' ')\n ```\nC. ```3 6 9 12 ``` \n??? success \"Correction\"\n ```python linenums='1'\n for k in range(3,13,3):\n print(k, end = ' ')\n ```\nD. ```10 9 8 7 6 5 4 3 2 1 0 ``` \n??? success \"Correction\"\n ```python linenums='1'\n for k in range(10,-1,-1):\n print(k, end = ' ')\n ```\n
"},{"location":"T1_Demarrer_en_Python/1.2_Boucle_for/cours/#5-une-situation-classique-la-double-boucle","title":"5. Une situation classique : la double boucle","text":"Il est tr\u00e8s souvent utile d'imbriquer une boucle dans une autre, notamment lors du parcours de tous les pixels d'une image. Prenons pour l'instant un exemple num\u00e9rique.
Exemple fondateur
Le programme suivant :
for a in range(1,5):\n for b in range(1,4):\n p = a * b\n print(a, '*', b, '=', p)\n
va donner ceci : 1 * 1 = 1\n1 * 2 = 2\n1 * 3 = 3\n2 * 1 = 2\n2 * 2 = 4\n2 * 3 = 6\n3 * 1 = 3\n3 * 2 = 6\n3 * 3 = 9\n4 * 1 = 4\n4 * 2 = 8\n4 * 3 = 12\n
Analyse gr\u00e2ce \u00e0 PythonTutor
Exercice 3
\u00c9nonc\u00e9Correction\u00c9crire un programme qui affiche :
Papa dit : \u00ab et une cuill\u00e8re pour Riri ! \u00bb\nPapa dit : \u00ab et une cuill\u00e8re pour Fifi ! \u00bb\nPapa dit : \u00ab et une cuill\u00e8re pour Loulou ! \u00bb\nMaman dit : \u00ab et une cuill\u00e8re pour Riri ! \u00bb\nMaman dit : \u00ab et une cuill\u00e8re pour Fifi ! \u00bb\nMaman dit : \u00ab et une cuill\u00e8re pour Loulou ! \u00bb\nMamie dit : \u00ab et une cuill\u00e8re pour Riri ! \u00bb\nMamie dit : \u00ab et une cuill\u00e8re pour Fifi ! \u00bb\nMamie dit : \u00ab et une cuill\u00e8re pour Loulou ! \u00bb\n
for parent in [\"Papa\", \"Maman\", \"Mamie\"]:\n for enfant in [\"Riri\", \"Fifi\", \"Loulou\"]:\n print(parent, \"dit : \u00ab et une cuill\u00e8re pour\", enfant, \"! \u00bb\")\n
Exercice 4
\u00c9nonc\u00e9CorrectionRajouter \u00e0 la phrase pr\u00e9c\u00e9dente le contenu de la cuill\u00e8re (pur\u00e9e puis compote).
Exemple :
Papa dit : \u00ab et une cuill\u00e8re de pur\u00e9e pour Riri ! \u00bb\nPapa dit : \u00ab et une cuill\u00e8re de compote pour Riri ! \u00bb\nPapa dit : \u00ab et une cuill\u00e8re de pur\u00e9e pour Fifi ! \u00bb\nPapa dit : \u00ab et une cuill\u00e8re de compote pour Fifi ! \u00bb\nPapa dit : \u00ab et une cuill\u00e8re de pur\u00e9e pour Loulou ! \u00bb\nPapa dit : \u00ab et une cuill\u00e8re de compote pour Loulou ! \u00bb\nMaman dit : \u00ab et une cuill\u00e8re de pur\u00e9e pour Riri ! \u00bb\nMaman dit : \u00ab et une cuill\u00e8re de compote pour Riri ! \u00bb\n...\n
for parent in [\"Papa\", \"Maman\", \"Mamie\"]:\n for enfant in [\"Riri\", \"Fifi\", \"Loulou\"]:\n for nourriture in [\"pur\u00e9e\", \"compote\"]:\n print(parent, \"dit : \u00ab et une cuill\u00e8re de\", nourriture, \"pour\", enfant, \"! \u00bb\")\n
"},{"location":"T1_Demarrer_en_Python/1.2_Boucle_for/cours/#6-pour-conclure","title":"6. Pour conclure","text":"\u00c0 retenir
for ... in ...
s'utilise lorsque :Les instructions r\u00e9p\u00e9t\u00e9es peuvent - mais ce n'est pas obligatoire - faire appel \u00e0 la variable de boucle, mais il ne faut pas que ces instructions la modifient.
Ne pas oublier les :
et l'indentation !
range(n)
g\u00e9n\u00e8re une s\u00e9quence de n
nombres entiers: on s'en servira d\u00e8s qu'on aura besoin de r\u00e9p\u00e9ter n
fois des instructions.for ... in
","text":"Exercice 1
\u00c9nonc\u00e9CorrectionOn donne une liste d'acteurs :
liste_acteurs = ['Tahar', 'Omar', 'Guillaume', 'Swann', 'Alex', 'Roschdy']\n
Utilisez cette liste pour produire la sortie suivante:
Tahar a eu le C\u00e9sar du meilleur acteur\nOmar a eu le C\u00e9sar du meilleur acteur\nGuillaume a eu le C\u00e9sar du meilleur acteur\nSwann a eu le C\u00e9sar du meilleur acteur\nAlex a eu le C\u00e9sar du meilleur acteur\nRoschdy a eu le C\u00e9sar du meilleur acteur\n
liste_acteurs = ['Tahar', 'Omar', 'Guillaume', 'Swann', 'Alex', 'Roschdy']\n\nfor acteur in liste_acteurs:\n print(acteur, \"a eu le C\u00e9sar du meilleur acteur\")\n
Concat\u00e9nation de caract\u00e8res
Il est possible de coller (le vrai mot est concat\u00e9ner) deux cha\u00eenes de caract\u00e8res par l'op\u00e9rateur +
:
>>> \"a\" + \"b\"\n'ab'\n
Exercice 2
\u00c9nonc\u00e9CorrectionDans l'extrait de code suivant:
chaine
est une variable initialis\u00e9e avec un str
vide : \"\"
;'bravo'
.L'id\u00e9e est d'ajouter une par une les lettres \u00e0 la variable chaine
.
\u00c0 l'ex\u00e9cution, le programme doit afficher uniquement bravo
.
Compl\u00e9ter le code.
chaine = \"\"\nfor ... in ['b', 'r', 'a', 'v', 'o']:\n ...\nprint(chaine)\n
Cette variable chaine
est appel\u00e9e un accumulateur.
chaine = \"\"\nfor lettre in ['b', 'r', 'a', 'v', 'o']:\n chaine += lettre\n\nprint(chaine)\n
Exercice 3
\u00c9nonc\u00e9CorrectionEn Python, la fonction ord
renvoie le code Unicode d'un caract\u00e8re et la fonction chr
le contraire: elle renvoie le caract\u00e8re correspondant \u00e0 un code Unicode.
Par exemple:
>>> ord('a')\n97\n>>> chr(97)\n'a'\n
Voici une liste contenant les codes Unicode des lettres d'un mot secret... \u00c0 vous d'\u00e9crire un programme o\u00f9 en sortie, la variable mot_secret
contiendra la cha\u00eene de caract\u00e8res de ce mot.
mystere = [111, 107, 44, 32, 98, 105, 101, 110, 32, 106, 111, 117, 233]\nmot_secret = \"\"\n
Exercice 4
\u00c9nonc\u00e9CorrectionOn souhaite calculer la somme des 1000 premiers nombres entiers naturels, c'est-\u00e0-dire:
\\(1+2+3+4+5+ \\dots +999+1000\\)
\u00c9crire un programme avec une variable somme
accumulateur (comme \u00e0 l'exercice 3) qui contiendra la valeur souhait\u00e9e en fin de programme.
somme = 0\nfor k in range(1, 1001):\n somme += k\nprint(somme)\n
Exercice 5
\u00c9nonc\u00e9CorrectionCalculer \\(1\\times 2 \\times 3 \\times \\dots 99 \\times 100\\).
produit = 1\nfor k in range(1,101):\n produit = produit * k\nprint(produit) \n
Exercice 6
\u00c9nonc\u00e9CorrectionProposer un code qui \u00e9crit la table de multiplication de 7, de 8 et de 9.
La sortie doit ressembler \u00e0 :
7*1 = 7\n\n7*2 = 14\n\n... \n...\n\n9*9 = 81 \n
for a in range(7, 10):\n for b in range(1, 10):\n print(a, '*', b, '=', a*b)\n
Exercice 7
\u00c9nonc\u00e9CorrectionSur un jeu d'\u00e9checs, les cases sont rep\u00e9r\u00e9es par une lettre (de A jusqu'\u00e0 H) et par un chiffre (de 1 jusqu'\u00e0 8).
Les cases sont donc A1, A2, A3, ..., H7, H8.
Proposer un code qui \u00e9crit toutes les cases possibles.
for lettre in \"ABCDEFGH\":\n for chiffre in \"12345678\":\n case = lettre + chiffre\n print(case)\n
Autre solution utilisant la conversion d'un entier en chaine de caract\u00e8res, gr\u00e2ce \u00e0 la fonction str
:
for lettre in \"ABCDEFGH\":\n for chiffre in range(1, 9):\n case = lettre + str(chiffre)\n print(case)\n
Exercice 8
Travail sur ipythonblocks
:
Exercice \u00e0 faire sur Capytale : https://capytale2.ac-paris.fr/web/c/8869-1863952
Exercice 9
\u00c9nonc\u00e9CorrectionDans ma trousse je dispose de 5 feutres de couleur :
Pour un exercice, je dois colorier 3 pastilles en choissant sans aucune contrainte des couleurs parmi les 5 disponibles. Je peux tout colorier en jaune (JJJ
) ou bien colorier la 1\u00e8re en orange, la 2\u00e8me en bleu, la 3\u00e8me en vert (OBV
)
Faire afficher la totalit\u00e9 des combinaisons possibles.
couleurs = \"JVNBO\"\nfor c1 in couleurs:\n for c2 in couleurs:\n for c3 in couleurs:\n print(c1 + c2 + c3)\n
"},{"location":"T1_Demarrer_en_Python/1.2_Boucle_for/exos_processing/","title":"Exercices sous Processing","text":""},{"location":"T1_Demarrer_en_Python/1.2_Boucle_for/exos_processing/#1-presentation-de-processing","title":"1. Pr\u00e9sentation de Processing","text":"Processing est un outil de cr\u00e9ation multim\u00e9dia utilisant le code informatique. Simple de prise en main, il a \u00e9t\u00e9 cr\u00e9\u00e9 par des artistes pour des artistes. On peut utiliser le langage Python pour entrer les instructions.
Nous l'utiliserons pour ajouter du graphisme \u00e0 nos cr\u00e9ations. Dans tous les exercices de cette page, les dessins r\u00e9alis\u00e9s seront statiques. Nous verrons plus tard comment Processing permet tr\u00e8s facilement de faire des animations.
Documentation"},{"location":"T1_Demarrer_en_Python/1.2_Boucle_for/exos_processing/#2-les-bases-de-processing","title":"2. Les bases de Processing","text":""},{"location":"T1_Demarrer_en_Python/1.2_Boucle_for/exos_processing/#21-repere","title":"2.1 Rep\u00e8re","text":"
\u00c0 l'ex\u00e9cution de tout script Processing, une fen\u00eatre s'affiche avec une zone de dessin. Sa taille se d\u00e9finit \u00e0 l'aide de la fonction size
. Par exemple, pour cr\u00e9er une zone de dessin de 300 pixels sur 200 pixels, on utilisera:
size(300, 200)\n
Chaque pixel de cette zone est rep\u00e9r\u00e9e par des coordonn\u00e9es dans le rep\u00e8re suivant, dont l'origine se situe en haut \u00e0 gauche et l'axe des ordonn\u00e9es est orient\u00e9 vers le bas.
"},{"location":"T1_Demarrer_en_Python/1.2_Boucle_for/exos_processing/#22-traces","title":"2.2 Trac\u00e9s","text":"
Trac\u00e9s de base
point
: permet de dessiner un point (pixel). En param\u00e8tre, les coordonn\u00e9es du point.line
: permet de tracer une ligne entre deux points. En param\u00e8tres, les coordonn\u00e9es des deux points.rect
: permet de tracer un rectangle. En param\u00e8tres, les coordonn\u00e9es du sommet haut-gauche, puis la largeur et la hauteur du rectangle.ellipse
: permet de tracer une ellipse. En param\u00e8tres, les coordonn\u00e9es du centre, puis la largeur et la hauteur (mettre la m\u00eame valeur pour un cercle).Copier-coller le code suivant et faire varier les param\u00e8tres pour bien les comprendre.
size(200, 200)\npoint(10, 60)\nline(10, 10, 100, 150)\nrect(80, 10, 20, 50)\nellipse(150, 100, 80, 40)\n
"},{"location":"T1_Demarrer_en_Python/1.2_Boucle_for/exos_processing/#23-couleurs","title":"2.3 Couleurs","text":"Pinceau
background
: permet de d\u00e9finir la couleur du fond de la zone de dessin. En param\u00e8tres, les trois composantes RGB de la couleur.stroke
: permet de d\u00e9finir la couleur du pinceau (noir par d\u00e9faut) pour le contour de la forme. En param\u00e8tres, les trois composantes RGB de la couleur.noStroke
: permet de dessiner une forme sans coutour (pas de param\u00e8tre).strokeWeight
: permet de d\u00e9finir la largeur du pinceau. En param\u00e8tre, le nombre de pixel.fill
: permet de d\u00e9finir la couleur de remplissage de la forme. En param\u00e8tres, les trois composantes RGB de la couleur.Copier-coller le code suivant et faire varier les param\u00e8tres pour bien les comprendre.
size(200, 200)\nbackground(255, 255, 255)\nstroke(255, 0, 0)\npoint(10, 60)\nline(10, 10, 100, 150)\nstroke(0, 127, 255)\nstrokeWeight(5)\nrect(80, 10, 20, 50)\nnoStroke()\nfill(204, 153, 204)\nellipse(150, 100, 80, 40)\n
"},{"location":"T1_Demarrer_en_Python/1.2_Boucle_for/exos_processing/#3-exercices-sur-la-simple-boucle","title":"3. Exercices sur la simple boucle","text":"Tous les exercices sont \u00e0 faire dans une fen\u00eatre de 300 pixels sur 300 pixels.
Exercice 1
\u00c9nonc\u00e9Correction en ProcessingCorrection en p5L'objectif est d'obtenir dix lignes al\u00e9atoires, de couleur al\u00e9atoire et d'\u00e9paisseur 10.
Aide
random(a,b)
permet d'obtenir un entier pseudo al\u00e9atoire entre a
et b
.size(300,300)\nbackground(0)\nfor k in range(10):\n Ax = random(0,300)\n Ay = random(0,300)\n Bx = random(0,300)\n By = random(0,300)\n strokeWeight(10)\n stroke(random(0,255), random(0,255), random(0,255))\n line(Ax,Ay,Bx,By)\n
from p5 import *\n\ndef setup():\n createCanvas(300, 300)\n noLoop()\n\ndef draw():\n background(0)\n for k in range(10):\n Ax = random(0,300)\n Ay = random(0,300)\n Bx = random(0,300)\n By = random(0,300)\n strokeWeight(10)\n stroke(random(0,255), random(0,255), random(0,255))\n line(Ax,Ay,Bx,By)\n\nrun()\n
Exercice 2 difficile
\u00c9nonc\u00e9Correction en ProcessingCorrection en p5Reprendre l'exercice pr\u00e9c\u00e9dent en faisant en sorte que chaque ligne commence l\u00e0 o\u00f9 une autre s'arr\u00eate (hormis la premi\u00e8re)
size(300,300)\nbackground(0)\nAx = random(0,300)\nAy = random(0,300)\nfor k in range(10):\n Bx = random(0,300)\n By = random(0,300)\n strokeWeight(10)\n stroke(random(0,255), random(0,255), random(0,255))\n line(Ax,Ay,Bx,By)\n Ax = Bx\n Ay = By\n
from p5 import *\n\ndef setup():\n createCanvas(300, 300)\n noLoop()\n\ndef draw():\n background(0)\n Ax = random(0,300)\n Ay = random(0,300)\n for k in range(10):\n Bx = random(0,300)\n By = random(0,300)\n strokeWeight(10)\n stroke(random(0,255), random(0,255), random(0,255))\n line(Ax,Ay,Bx,By)\n Ax = Bx\n Ay = By\n\nrun()\n
Exercice 3
\u00c9nonc\u00e9Correction en ProcessingCorrection en p5Tracer 50 disques de position, diam\u00e8tre, couleur et transparence al\u00e9atoires.
Aide
size(300,300)\nbackground(0)\nfor k in range(50):\n Ax = random(0,300)\n Ay = random(0,300)\n diametre = random(0,50)\n noStroke()\n r = random(0,255)\n g = random(0,255)\n b = random(0,255)\n a = random(0,255)\n fill(r, g, b, a)\n ellipse(Ax,Ay,diametre, diametre)\n
from p5 import *\n\ndef setup():\n createCanvas(300, 300)\n noLoop()\n\ndef draw():\n background(0)\n for k in range(50):\n Ax = random(0,300)\n Ay = random(0,300)\n diametre = random(0,50)\n noStroke()\n r = random(0,255)\n g = random(0,255)\n b = random(0,255)\n a = random(0,255)\n fill(r, g, b, a)\n ellipse(Ax,Ay,diametre, diametre)\n\nrun()\n
Exercice 4 \u00e0 faire sur Capytale : activit\u00e9 55f1-63735
Lire obligatoirement au pr\u00e9alable la page \u00abComment passer d'un code Processing \u00e0 un code p5\u00bb
\u00c9nonc\u00e9Proposer un code r\u00e9alisant la figure suivante. Votre code devra obligatoirement comporter une boucle for
.
La structure de double boucle va permettre (par exemple) de parcourir l'int\u00e9gralit\u00e9 des pixels d'une image.
Exercices \u00e0 faire sur Capytale : activit\u00e9 38d9-68425
Exercice 5
Construire une image o\u00f9 tous les points ont une couleur al\u00e9atoire.
Exercice 6
Construire une image constitu\u00e9e de carr\u00e9s de 20 pixels de cot\u00e9, de couleur al\u00e9atoire. L'image est toujours un carr\u00e9 de c\u00f4t\u00e9 300 pixels.
"},{"location":"T1_Demarrer_en_Python/1.3_Boucle_while/cours/","title":"1.3 Boucle While","text":""},{"location":"T1_Demarrer_en_Python/1.3_Boucle_while/cours/#1-premiers-exemples","title":"1. Premiers exemples","text":"\u00c0 la diff\u00e9rence essentielle des boucles for
, dont on peut savoir \u00e0 l'avance combien de fois elles vont \u00eatre ex\u00e9cut\u00e9es, les boucles while
sont des boucles dont on ne sort que lorsqu'une condition n'est plus satisfaite.
Avec donc le risque de rester infiniment bloqu\u00e9 \u00e0 l'int\u00e9rieur !
Exemple fondateur n\u00b01
Le programme suivant :
a = 0\nwhile a < 3:\n print(\"ok\")\n a = a + 1\nprint(\"fini\")\n
va donner ceci : ok\nok\nok\nfini\n
Analyse gr\u00e2ce \u00e0 PythonTutor
Question
le code ci-dessous va-t-il donner un r\u00e9sultat diff\u00e9rent ?
a = 0\nwhile a < 3:\n a = a + 1\n print(\"ok\")\nprint(\"fini\")\n
R\u00e9sultat du programme \u23ec ok\nok\nok\nfini\n
Conclusion : l'\u00e9valuation de la condition ne se fait pas \u00e0 chaque ligne mais bien au d\u00e9but de chaque tour de boucle. Si la variable qui d\u00e9clenchera la sortie de boucle atteint sa valeur de sortie au milieu des instructions, les lignes restantes sont quand m\u00eame ex\u00e9cut\u00e9es.
"},{"location":"T1_Demarrer_en_Python/1.3_Boucle_while/cours/#2-syntaxe-generale","title":"2. Syntaxe g\u00e9n\u00e9rale","text":"\u00c9criture d'une boucle while
while condition:\n instruction1\n instruction2\n ...\n instructionN\n
"},{"location":"T1_Demarrer_en_Python/1.3_Boucle_while/cours/#21-la-condition","title":"2.1 La condition","text":"La condition
est un bool\u00e9en, c'est-\u00e0-dire une expression que Python \u00e9valuera \u00e0 True
ou \u00e0 False
.
Exemple de bool\u00e9ens r\u00e9sultant d'une \u00e9valuation :
>>> 1 < 3\nTrue\n>>> 5 > 7\nFalse\n>>> a = 10\n>>> a > 8\nTrue\n
Un cours sur les bool\u00e9ens aura lieu ici.
"},{"location":"T1_Demarrer_en_Python/1.3_Boucle_while/cours/#22-les-instructions","title":"2.2 Les instructions","text":"Les instructions instruction1
jusqu'\u00e0 instructionN
sont ex\u00e9cut\u00e9es dans cet ordre \u00e0 chaque tour de boucle.
Attention : ces instructions doivent obligatoirement avoir un impact sur la condition
\u00e9valu\u00e9e apr\u00e8s le while
(dans le cours sur la dichotomie, nous \u00e9voquerons la notion de variant de boucle).
Voir le pi\u00e8ge n\u00b01 ...
"},{"location":"T1_Demarrer_en_Python/1.3_Boucle_while/cours/#3-les-pieges","title":"3. Les pi\u00e8ges ...","text":""},{"location":"T1_Demarrer_en_Python/1.3_Boucle_while/cours/#31-piege-n1-ne-jamais-sortir-de-la-boucle","title":"3.1 pi\u00e8ge n\u00b01 : ne JAMAIS SORTIR de la boucle","text":"Exemple fondateur n\u00b02
Le programme suivant :
a = 0\nwhile a < 3:\n print(\"ok\")\n a = a + 1\n a = a * 0\nprint(\"ce texte ne s'\u00e9crira jamais\")\n
va \u00e9crire une suite infinie de ok
et ne jamais s'arr\u00eater"},{"location":"T1_Demarrer_en_Python/1.3_Boucle_while/cours/#32-piege-n2-ne-jamais-entrer-dans-la-boucle","title":"3.2 pi\u00e8ge n\u00b02 : ne JAMAIS ENTRER dans la boucle","text":"Exemple fondateur n\u00b03
Le programme suivant :
a = 0\nwhile a > 10:\n print(\"ce texte non plus ne s'\u00e9crira jamais\")\n a = a + 1\n\nprint(\"fini\") \n
va \u00e9crire fini
et s'arr\u00eater.
Exercice 1
\u00c9nonc\u00e9CorrectionTrouver le plus petit nombre entier \\(n\\) tel que \\(2^n\\) soit sup\u00e9rieur \u00e0 1 milliard.
n = 1\nwhile 2**n < 10**9:\n n = n + 1\n print(\"trop petit\")\nprint(\"trouv\u00e9 : \",n)\n
"},{"location":"T1_Demarrer_en_Python/1.3_Boucle_while/cours/#4-quelques-remarques","title":"4. Quelques remarques","text":""},{"location":"T1_Demarrer_en_Python/1.3_Boucle_while/cours/#41-lien-entre-while-et-for","title":"4.1 Lien entre while
et for
","text":"La boucle born\u00e9e for
que nous avons \u00e9tudi\u00e9e est tr\u00e8s pratique.
Mais nous pourrions nous en passer : toutes les boucles for
peuvent en fait \u00eatre r\u00e9-\u00e9crites en utilisant while
. (alors que la r\u00e9ciproque est fausse)
Exercice 2
\u00c9nonc\u00e9CorrectionOn consid\u00e8re le code ci-dessous :
for k in range(5):\n print(\"scooby-doo\")\n
R\u00e9-\u00e9crire ce code en utilisant une boucle while
. k = 0\nwhile k < 5:\n print(\"scooby-doo\")\n k = k + 1\n
"},{"location":"T1_Demarrer_en_Python/1.3_Boucle_while/cours/#42-les-boucles-infinies-volontaires","title":"4.2 Les boucles infinies volontaires","text":"La boucle infinie a \u00e9t\u00e9 pr\u00e9sent\u00e9e comme un danger qu'il faut \u00e9viter.
Pourtant, dans quelques situations, il est d'usage d'enfermer volontairement l'utilisateur dans une boucle infinie.
C'est notamment le cas des codes Processing (ou p5) o\u00f9 la fonction draw()
est une boucle infinie dont on ne sort que lorsqu'un \u00e9v\u00e8nement est intercept\u00e9 (par exemple, le clic sur la fermeture de la fen\u00eatre d'affichage).
Observez et ex\u00e9cutez le code suivant :
while True :\n reponse = input(\"tapez sur la lettre S du clavier pour me sortir de cet enfer : \")\n if reponse == 'S' or reponse == 's':\n break\n\nprint(\"merci, j'\u00e9tais bloqu\u00e9 dans une boucle infinie\")\n
while True
est typique des boucles infinies volontaires. On aurait tout aussi bien pu \u00e9crire while 3 > 2
(on rencontre m\u00eame parfois des while 1
)break
qui comme son nom l'indique permet de casser la boucle (cela marche pour while
comme pour for
) et donc d'en sortir. Son emploi est controvers\u00e9 parmi les puristes de la programmation. Nous dirons juste que c'est une instruction bien pratique.Exercice 3
\u00c9nonc\u00e9CorrectionProposer un code qui choisit un nombre al\u00e9atoire entre 1 et 100, puis qui propose en boucle \u00e0 l'utilisateur de le deviner, tant que celui-ci n'a pas trouv\u00e9.
On donnera \u00e0 l'utilisateur des instructions \"trop grand !\" ou \"trop petit !\" pour le guider.
Aides :
int()
permet de convertir une cha\u00eene de caract\u00e8res en nombre. a
pseudo-al\u00e9atoire : from random import randint\na = randint(1,10)\n
from random import randint\n\nmystere = randint(1, 100)\n\nwhile True:\n reponse = int(input('quel est le nombre myst\u00e8re ? '))\n if reponse > mystere:\n print('trop grand !')\n elif reponse < mystere:\n print('trop petit !')\n else:\n print('bravo !')\n break\n
Exercice 4
\u00c9nonc\u00e9CorrectionEn vous basant sur l'exercice pr\u00e9c\u00e9dent, code un programme d'entra\u00eenement aux tables de multiplication de 1 \u00e0 10.
"},{"location":"T1_Demarrer_en_Python/1.4_Instruction_conditionnelle_if/cours/","title":"1.4 Instruction conditionnelle if","text":"L'instruction conditionnelle if
permet de soumettre l'ex\u00e9cution d'instructions \u00e0 une condition donn\u00e9e. Cette condition sera une expression bool\u00e9enne, comme pour la boucle while
.
Dans les exemples ci-dessous, changez la valeur affect\u00e9e \u00e0 la variable age
afin d'observer les modifications de comportement du programme.
Exemple fondateur n\u00b01
L'exemple minimal ci-dessous ne contient que le mot-cl\u00e9 if
.
age = 20\nif age >= 18:\n print(\"Tu as le droit de vote\")\n
Exemple fondateur n\u00b02
La structure qu'on rencontrera le plus souvent est la structure if ... else ...
age = 20\nif age >= 18:\n print(\"Tu as le droit de vote\")\nelse:\n print(\"D\u00e9sol\u00e9, il faudra attendre\", 18 - age, \"ans avant de pouvoir voter\")\n
Syntaxe g\u00e9n\u00e9rale
if expression bool\u00e9enne:\n *instructions \u00e0 effectuer si l'expression est vraie*\nelse:\n *instructions \u00e0 effectuer si l'expression est fausse*\n
"},{"location":"T1_Demarrer_en_Python/1.4_Instruction_conditionnelle_if/cours/#2-levaluation-de-la-condition","title":"2. L'\u00e9valuation de la condition","text":"Comme pour la boucle while
, on dit que l'expression qui suit le if
est \u00e9valu\u00e9e par Python lors de l'ex\u00e9cution du programme.
Cette \u00e9valuation renvoie un bool\u00e9en, True
ou False
.
Les symboles de comparaison (ou d'appartenance) permettant d'\u00e9crire une condition sont :
Op\u00e9rateurs de comparaison
Op\u00e9rateur Signification==
est \u00e9gal \u00e0 !=
est diff\u00e9rent de <
inf\u00e9rieur \u00e0 >
sup\u00e9rieur \u00e0 <=
inf\u00e9rieur ou \u00e9gal \u00e0 >=
sup\u00e9rieur ou \u00e9gal \u00e0 in
appartient \u00e0 not in
n'appartient pas \u00e0 Exemples
>>> a = 2\n\n>>> a == 3\nFalse\n\n>>> a == 2\nTrue\n\n>>> a != 1\nTrue\n\n>>> a > 2\nFalse\n\n>>> a >= 2\nTrue\n\n>>> a <= 2\nTrue\n\n>>> a <= 5\nTrue\n\n>>> 'e' in 'abracadabra'\nFalse\n\n>>> 'b' in 'abracadabra'\nTrue\n\n>>> 'A' not in 'abracadabra'\nTrue\n\n>>> not True\nFalse\n
Comme nous le verrons dans le cours sur les bool\u00e9ens, ces conditions peuvent \u00eatre combin\u00e9es avec (par exemple) les mots-cl\u00e9s and
ou or
:
>>> b = 20\n>>> b > 15 and b < 30\nTrue\n>>> b > 2000 or b < 30\nTrue\n
Exercice
\u00c9nonc\u00e9CorrectionCompter le nombre de voyelles de la phrase 'cet exercice est prodigieusement ennuyeux'
phrase = 'cet exercice est prodigieusement ennuyeux'\nvoyelles = 'aeiouy'\n
phrase = 'cet exercice est prodigieusement ennuyeux'\nvoyelles = 'aeiouy'\n\ncompteur = 0\n\nfor lettre in phrase:\n if lettre in voyelles:\n compteur += 1\n\nprint(compteur)\n
"},{"location":"T1_Demarrer_en_Python/1.4_Instruction_conditionnelle_if/cours/#3-un-test-tres-frequent-le-test-de-divisibilite","title":"3. Un test tr\u00e8s fr\u00e9quent : le test de divisibilit\u00e9","text":"Exemple fondateur n\u00b03
Pour tester si un nombre n
est divisible par un nombre d
, on teste si le reste de la division euclidienne de n
par d
est \u00e9gal \u00e0 0 :
n = 17\nif n % 2 == 0:\n print(n, \"est un nombre pair\")\nelse:\n print(n, \"est un nombre impair\")\n
Exercice
\u00c9nonc\u00e9CorrectionAfficher la liste de tous les nombres entre 1 et 100 qui sont divisibles \u00e0 la fois par 2 et par 7.
for n in range(1,101):\n if n % 2 == 0 and n % 7 == 0:\n print(n)\n
"},{"location":"T1_Demarrer_en_Python/1.4_Instruction_conditionnelle_if/cours/#4-les-cas-multiples-utilisation-de-elif","title":"4. Les cas multiples : utilisation de elif
","text":"Dans les situations o\u00f9 l'on veut effectuer des instructions diff\u00e9rentes selon les diff\u00e9rentes valeurs prises par une variable, on peut imbriquer les instructions if
... else
.
Observer par exemple le code ci-dessous :
moyenne = 13\n\nif moyenne < 8:\n print(\"rat\u00e9\")\nelse:\n if moyenne < 10:\n print(\"rep\u00eachage\")\n else:\n if moyenne < 12:\n print(\"admis\")\n else:\n if moyenne < 14:\n print(\"mention AB\")\n else:\n if moyenne < 16:\n print(\"mention B\")\n else:\n print(\"mention TB\")\n
Mais cela est vite long et peu lisible, et les diff\u00e9rents niveaux d'indentation peuvent devenir pi\u00e9geux.
Il existe alors une instruction qui contracte else
et if
: elif
(sinon si).
Ce code devient alors
moyenne = 7\n\nif moyenne < 8:\n print(\"rat\u00e9\")\nelif moyenne < 10:\n print(\"rep\u00eachage\")\nelif moyenne < 12:\n print(\"admis\")\nelif moyenne < 14:\n print(\"mention AB\")\nelif moyenne < 16:\n print(\"mention B\")\nelse:\n print(\"mention TB\")\n
"},{"location":"T1_Demarrer_en_Python/1.4_Instruction_conditionnelle_if/cours/#4-recreation-a-vous-dobeir","title":"4. R\u00e9cr\u00e9ation : \u00e0 vous d'ob\u00e9ir !","text":"Le site https://compute-it.toxicode.fr/ vous demande d'ex\u00e9cuter mentalement les instructions affich\u00e9es, \u00e0 l'aide des touches directionnelles de votre clavier. Attention, ce site est tr\u00e8s addictif !
"},{"location":"T1_Demarrer_en_Python/1.4_Instruction_conditionnelle_if/exercices/","title":"Exercices","text":"Exercice 1
\u00c9nonc\u00e9Correction\u00c9crire un programme qui demande deux nombres et qui affiche le plus grand des deux.
Aide : pour stocker dans une variable n
un nombre tap\u00e9 au clavier par l'utilisateur, on utilise le code suivant :
n = int(input('Entrez un nombre'))\n
Exemples d'utilisation du programme :
Premier nombre ? 12\nDeuxi\u00e8me nombre ? 45\nle nombre le plus grand est 45\n
Premier nombre ? 17\nDeuxi\u00e8me nombre ? 17\nles deux nombres sont \u00e9gaux\n
n1 = int(input('Premier nombre ?'))\nn2 = int(input('Deuxi\u00e8me nombre ?'))\n\nif n1 > n2:\n print('le nombre le plus grand est', n1)\nelif n2 > n1:\n print('le nombre le plus grand est', n2)\nelse:\n print('les deux nombres sont \u00e9gaux')\n
Exercice 2
\u00c9nonc\u00e9CorrectionLe jeu du FizzBuzz : il s'agit de compter \u00e0 partir de 1 en rempla\u00e7ant certains nombres par Fizz, Buzz ou Fizzbuzz :
\u00c9crire un code qui joue au FizzBuzz jusqu'\u00e0 50.
Exemple d'utilisation du programme :
1\n2\nfizz\n4\nbuzz\nfizz\n7\n8\n...\n
for k in range(1, 20):\n if k % 3 == 0 and k % 5 == 0:\n print('fizzbuzz')\n elif k % 3 == 0:\n print('fizz')\n elif k % 5 == 0:\n print('buzz')\n else:\n print(k)\n
Exercice 3
\u00c9nonc\u00e9CorrectionUne ann\u00e9e est d\u00e9clar\u00e9e bissextile (et compte donc 366 jours au lieu de 365) si elle est :
\u00c9crire un code qui d\u00e9termine si une ann\u00e9e est bissextile ou non.
Explication : la Terre faisant le tour du Soleil en un peu plus que 365 jours, on s'est dit qu'on allait rajouter un jour tous les 4 ans, mais c'\u00e9tait trop, alors on a enlev\u00e9 un jour tous les 100 ans, mais c'\u00e9tait plus assez, alors on a rajout\u00e9 un jour tous les 400 ans, ce qui donne une approximation convenable.
```python linenums='1' annee = int(input(\"ann\u00e9e ? \"))
if annee % 400 == 0: print(annee, 'est bissextile') elif annee % 4 == 0 and annee % 100 != 0: print(annee, 'est bissextile') else: print(annee, \"n'est pas bissextile\")
"},{"location":"T1_Demarrer_en_Python/1.5_Fonctions/cours/","title":"1.5 Fonctions","text":"La notion de fonction est essentielle en programmation. Elle permet de construire des codes modulaires, plus faciles \u00e0 lire et \u00e0 modifier. En Python, une fonction se cr\u00e9e avec le mot-cl\u00e9 def
.
Exemple fondateur n\u00b01
def accueil():\n print(\"bonjour\")\n print(\"comment allez-vous ?\")\n
Lorsque l'interpr\u00e9teur Python parcourt cette fonction, rien ne s'affiche : la fonction est maintenant pr\u00eate \u00e0 \u00eatre appel\u00e9e, mais n'est pas ex\u00e9cut\u00e9e tant que l'utilisateur ne le demande pas explicitement.
Ce sera le cas pour toutes les fonctions : elles doivent \u00eatre appel\u00e9es pour s'ex\u00e9cuter.
>>> accueil()\nbonjour\ncomment allez-vous ?\n
Dans ce cas d'utilisation, la fonction accueil
n'est qu'un raccourci, une factorisation d'un ensemble d'instructions.
Exemple fondateur n\u00b02
def chat_penible(n):\n for k in range(n):\n print(\"meoww\")\n
>>> chat_penible(3)\nmeoww\nmeoww\nmeoww\n
Vocabulaire
n
est appel\u00e9e param\u00e8tre de la fonction chat_penible
.n
\u00e0 la fonction chat_penible
.chat_penible
avec l'argument 3.Remarques :
print()
est une fonction \u00e0 param\u00e8tre, qui affiche dans la console le contenu du param\u00e8tre.Une fonction peut avoir de multiples param\u00e8tres :
Exemple fondateur n\u00b02
def repete(mot, k):\n for i in range(k):\n print(mot)\n
>>> repete(\"NSI\", 3)\nNSI\nNSI\nNSI\n
L'ordre des param\u00e8tres pass\u00e9s est alors important ! Le code ci-dessous est incorrect.
>>> repete(3, \"test\")\n---------------------------------------------------------------------------\n\nTypeError Traceback (most recent call last)\n\n<ipython-input-9-a84914f8a6c6> in <module>()\n----> 1 repete(3, \"test\")\n\n\n<ipython-input-8-7dc8032e3f17> in repete(mot, k)\n 1 def repete(mot, k) :\n----> 2 for i in range(k):\n 3 print(mot)\n 4 \n 5 repete(\"NSI\", 5)\n\n\nTypeError: 'str' object cannot be interpreted as an integer\n
"},{"location":"T1_Demarrer_en_Python/1.5_Fonctions/cours/#3-fonction-avec-parametres-et-avec-valeur-renvoyee","title":"3. Fonction avec param\u00e8tre(s) et avec valeur renvoy\u00e9e","text":"On retrouve ici la notion classique de fonction rencontr\u00e9e en math\u00e9matiques : un proc\u00e9d\u00e9 qui prend un nombre et en renvoie un autre. En informatique, l'objet renvoy\u00e9 ne sera pas forc\u00e9ment un nombre (cela pourra \u00eatre aussi une liste, un tableau, une image...). Le renvoi d'une valeur se fait gr\u00e2ce au mot-cl\u00e9 return
.
Exemple fondateur n\u00b03
La fonction math\u00e9matique \\(f : x \\longmapsto 2x+3\\) se codera par :
def f(x):\n return 2*x + 3\n
>>> f(10)\n23\n
"},{"location":"T1_Demarrer_en_Python/1.5_Fonctions/cours/#4-autour-du-return","title":"4. Autour du return
","text":""},{"location":"T1_Demarrer_en_Python/1.5_Fonctions/cours/#41-la-force-du-return","title":"4.1 La force du return
","text":"Diff\u00e9rence fondamentale entre return
et print
Le mot-cl\u00e9 return
de l'exemple pr\u00e9c\u00e9dent fait que l'expression f(10)
est \u00e9gale \u00e0 23. On peut d'ailleurs \u00e9crire en console :
>>> f(10) + 5\n28\n
Imaginons (avant de l'oublier tr\u00e8s vite) le code affreux ci-dessous : def g(x):\n print(2*x + 3)\n
On pourrait avoir l'illusion que la fonction g
fait correctement son travail : >>> g(10)\n23\n
Mais g
se contente d'afficher sa valeur calcul\u00e9e, et non pas de la renvoyer. En effet : >>> g(10) + 5\n23\nTraceback (most recent call last):\nFile \"<pyshell>\", line 1, in <module>\nTypeError: unsupported operand type(s) for +: 'NoneType' and 'int'\n
En r\u00e9sum\u00e9 : "},{"location":"T1_Demarrer_en_Python/1.5_Fonctions/cours/#42-le-return-est-un-siege-ejectable","title":"4.2 Le return
est un si\u00e8ge \u00e9jectable","text":"Le mot-cl\u00e9 return
provoque une \u00e9jection du code : tout ce qui est situ\u00e9 apr\u00e8s le \u00a0return
ne sera pas ex\u00e9cut\u00e9. Observez la diff\u00e9rence entre les fonctions g
et h
.
def g(x):\n print(\"ce texte sera bien affich\u00e9\")\n return 2*x+3\n
>>> g(4)\nce texte sera bien affich\u00e9\n11\n
def h(x):\n return 2*x+3\n print(\"ceci ne sera jamais affich\u00e9\")\n
>>> h(4)\n11\n
"},{"location":"T1_Demarrer_en_Python/1.5_Fonctions/cours/#43-les-fonctions-sans-return-sont-elles-des-fonctions","title":"4.3 Les fonctions sans return
sont-elles des fonctions ?","text":"Pour les puristes, une fonction sans valeur renvoy\u00e9e sera plut\u00f4t appel\u00e9e proc\u00e9dure. Le mot fonction est alors r\u00e9serv\u00e9 aux fonctions qui ont effectivement un return
.
On peut doter artificiellement \u00e0 toutes les fonctions d'un return
, en renvoyant la valeur None
:
def chat_penible(n):\n for k in range(n):\n print(\"meoww\")\n return None\n
D\u00e9finitions
On dit que les fonctions cr\u00e9ent leur \u00abespace de noms\u00bb (espace est \u00e0 prendre au sens d'univers), un espace qui leur est propre.
Quelles sont les r\u00e8gles r\u00e9gissant ces espaces de noms ? Les fronti\u00e8res entre ces espaces sont elles poreuses ?
"},{"location":"T1_Demarrer_en_Python/1.5_Fonctions/cours/#52-regles-dacces-en-lecture-et-en-modification-dune-variable-suivant-son-espace-dorigine","title":"5.2 R\u00e8gles d'acc\u00e8s en lecture et en modification d'une variable suivant son espace d'origine","text":"R\u00e8gles d'acc\u00e8s aux variables locales et globales
Exercice
\u00c9nonc\u00e9Correction code ACorrection code BCorrection code COn consid\u00e8re les 3 codes ci-dessous. Pour chacun, dire sans l'ex\u00e9cuter s'il est valide ou non. S'il ne l'est pas, identifier la r\u00e8gle (parmi celles \u00e9nonc\u00e9es ci-dessus) qui est bafou\u00e9e.
code A
points = 0\ndef verdict(reponse):\n if reponse > 10:\n points += 3\n\nverdict(12)\n
code B
def bouge(x, decalage):\n x += decalage\n\nbouge(100, 5)\nprint(x)\n
code C
def test_bac(moyenne):\n if moyenne >= 10:\n print(\"admis !\")\n\ndef coup_de_pouce(note):\n return note + bonus\n\nbonus = 0.6\nma_moyenne = 9.5\nma_moyenne = coup_de_pouce(ma_moyenne)\ntest_bac(ma_moyenne)\n
Ce code n'est pas valide, car il contrevient \u00e0 la r\u00e8gle 3.
ligne 4
: la modification de la variable globale points
est interdite.
Ce code n'est pas valide, car il contrevient \u00e0 la r\u00e8gle 1.
ligne 5
: l'acc\u00e8s \u00e0 la variable locale x
est interdit.
Ce code est valide.
ligne 6
: l'acc\u00e8s \u00e0 la variable globale bonus
est autoris\u00e9, selon la r\u00e8gle 2.
\u00c0 propos de la r\u00e8gle n\u00b03
(toute la v\u00e9rit\u00e9, rien que la v\u00e9rit\u00e9)
Pour certains types de variables (listes, dictionnaires...), la modification d'une variable globale \u00e0 l'int\u00e9rieur du corps d'une fonction est en fait possible (contrairement \u00e0 ce qu'\u00e9nonce la r\u00e8gle 3). Mais cela reste tr\u00e8s fortement d\u00e9conseill\u00e9.
Pour les autres types de variables, on peut m\u00eame forcer pour avoir cette possibilit\u00e9 en utilisant le mot global
\u00e0 l'int\u00e9rieur de la fonction.
Mais il faut essayer d'\u00e9viter ceci. Une fonction ne doit (c'est un ordre, mais vous pouvez choisir de l'ignorer, tout comme vous pouvez choisir de passer au feu rouge) modifier que les variables qu'elle cr\u00e9e (ses variables locales) ou bien les variables qu'on lui a donn\u00e9es en param\u00e8tre.
Une fonction qui ne respecte pas cette r\u00e8gle pr\u00e9sente des effets de bord : on peut peut-\u00eatre arriver \u00e0 les g\u00e9rer sur un \u00abpetit\u00bb code, mais cela devient illusoire sur un code utilisant de multiples fonctions.
.
En r\u00e9sum\u00e9
Ne pas faire cela :
# PAS BIEN\nscore = 0\ndef ramasse_objet(objet):\n global score\n if objet == \"champignon\":\n score += 20\n if objet == \"banane\":\n score -= 300\n
>>> ramasse_objet(\"champignon\")\n>>> score\n20\n
Faire plut\u00f4t ceci :
# BIEN\nscore = 0\ndef ramasse_objet(objet, score): # ma fonction veut modifier score ? \n if objet == \"champignon\": # -> ok, je mets score dans ses param\u00e8tres\n score += 20\n if objet == \"banane\":\n score -= 300\n return score # je renvoie le nouveau score\n
>>> score = ramasse_objet(\"champignon\", score)\n>>> score\n20\n
"},{"location":"T1_Demarrer_en_Python/1.5_Fonctions/cours/#6-documenter-une-fonction","title":"6. Documenter une fonction","text":""},{"location":"T1_Demarrer_en_Python/1.5_Fonctions/cours/#61-help","title":"6.1 Help !","text":"Si une fonction peut \u00eatre assimil\u00e9e \u00e0 un outil, il est normal de se demander si cet outil poss\u00e8de un mode d'emploi.
Observons les fonctions pr\u00e9-d\u00e9finies par Python, et notamment une des premi\u00e8res que nous avons rencontr\u00e9es : la fonction print()
. Son mode d'emploi est accessible gr\u00e2ce \u00e0 la commande help(print)
.
>>> help(print)\nHelp on built-in function print in module builtins:\n\nprint(...)\n print(value, ..., sep=' ', end='\\n', file=sys.stdout, flush=False)\n\n Prints the values to a stream, or to sys.stdout by default.\n Optional keyword arguments:\n file: a file-like object (stream); defaults to the current sys.stdout.\n sep: string inserted between values, default a space.\n end: string appended after the last value, default a newline.\n flush: whether to forcibly flush the stream\n
Pensez \u00e0 utiliser cette fonction help()
(en d'autres termes, RTFM)
Il est possible, voire souhaitable (d\u00e8s qu'on cr\u00e9\u00e9 un code comportant plusieurs fonctions, et/ou qui sera amen\u00e9 \u00e0 \u00eatre lu par d'autres personnes), de cr\u00e9er un mode d'emploi pour ses fonctions. On appelle cela \u00e9crire la docstring de la fonction, et c'est tr\u00e8s simple : il suffit de l'encadrer par des triples double-quotes \"\"\"
.
Exemple
def chat_penible(n):\n\"\"\"\n Affiche n fois la chaine de caract\u00e8res \"meoww\"\n \"\"\"\n for k in range(n):\n print(\"meoww\")\n
On peut donc maintenant demander de l'aide pour cette fonction :
>>> help(chat_penible)\nHelp on function chat_penible in module __main__:\n\nchat_penible(n)\n Affiche n fois la chaine de caract\u00e8res \"meoww\"\n
Plus de renseignements sur les docstrings ici
"},{"location":"T1_Demarrer_en_Python/1.5_Fonctions/cours/#7-jeux-de-tests-pour-une-fonction","title":"7. Jeux de tests pour une fonction","text":"Les exercices de cette feuille sont (presque) tous livr\u00e9s avec un jeu de tests. Il s'agit d'une fonction, souvent appel\u00e9e test_nom_de_la fonction()
, qui va regrouper les diff\u00e9rents tests qu'on pourrait faire en console pour v\u00e9rifier que la fonction a le comportement d\u00e9sir\u00e9.
Ces tests reposent sur le mot-cl\u00e9 assert
, qui va lever une erreur lorsqu'il est suivi d'une expression \u00e9valu\u00e9e \u00e0 False
:
>>> assert 3 > 2\n>>> assert 3 > 5\nTraceback (most recent call last):\n File \"<pyshell>\", line 1, in <module>\nAssertionError\n>>> assert True\n>>> assert False\nTraceback (most recent call last):\n File \"<pyshell>\", line 1, in <module>\nAssertionError\n
Exemple d'un jeu de tests
def maxi(n1, n2):\n if n1 < n2 :\n return n2\n else :\n return n1\n\ndef test_maxi():\n assert maxi(3,4) == 4\n assert maxi(5,2) == 5\n assert maxi(7,7) == 7\n print(\"tests ok\")\n
Il faut v\u00e9rifier que les tests couvrent toutes les situations possibles, mais ce n'est pas toujours facile !
Exercice
\u00c9nonc\u00e9CorrectionOn consid\u00e8re (\u00e0 nouveau !) le jeu du FizzBuzz.
Rappel des r\u00e8gles
On souhaite \u00e9crire la fonction fizzbuzz(n)
qui renverra soit le nombre n
, soit le mot par lequel il faut le remplacer.
test_fizzbuzz()
qui testera la fonction fizzbuzz(n)
.fizzbuzz(n)
.def test_fizzbuzz():\n assert fizzbuzz(6) == 'fizz'\n assert fizzbuzz(10) == 'buzz'\n assert fizzbuzz(15) == 'fizzbuzz'\n print('tests ok !')\n\ndef fizzbuzz(n):\n if n % 3 == 0 and n % 5 == 0:\n return 'fizzbuzz'\n elif n % 3 == 0:\n return 'fizz'\n elif n % 5 == 0:\n return 'buzz'\n else:\n return n\n
"},{"location":"T1_Demarrer_en_Python/1.5_Fonctions/exercices/","title":"Exercices","text":"Exercice 1
\u00c9nonc\u00e9Tester sa fonctionCorrection\u00c9crire une fonction maxi
qui prend comme param\u00e8tres deux nombres n1
et n2
et qui renvoie le plus grand \u00e9l\u00e9ment entre n1
et n2
.
Exemple d'utilisation
>>> maxi(3,1)\n3\n
Vous pouvez utiliser la fonction de tests ci-dessous :
def test_maxi():\n assert maxi(3,4) == 4\n assert maxi(5,2) == 5\n assert maxi(7,7) == 7\n print(\"tests ok\")\n
def maxi(n1, n2):\n if n1 < n2 :\n return n2\n else :\n return n1\n
Exercice 2
\u00c9nonc\u00e9Correction\u00c9crire une fonction moyenne
qui prend en param\u00e8tre trois nombres a
, b
et c
et qui renvoie la moyenne de ces trois nombres.
Exemple d'utilisation
>>> moyenne(6, 15, 9)\n10\n
def moyenne(a, b, c):\n return (a + b + c) / 3 \n
Exercice 3
\u00c9nonc\u00e9Correction\u00c9crire une fonction somme
qui prend en param\u00e8tre un entier positif n
et qui renvoie la somme de tous les entier de 1 \u00e0 n
.
\\(S = 1+2+3+4+5+ \\dots +(n-1) + n\\)
Exemple d'utilisation
>>> somme(10)\n55\n
def somme(n):\n s = 0\n for k in range(1, n+1):\n s += k\n return s\n
Exercice 4
\u00c9nonc\u00e9Tester sa fonctionCorrection\u00c9crire une fonction nb_voyelles
qui prend un param\u00e8tre la chaine de caract\u00e8res mot
renvoie le nombre de voyelles de mot
.
Exemple d'utilisation
>>> nb_voyelles(\"bonjour\")\n3\n
Vous pouvez utiliser la fonction de tests ci-dessous :
def test_nb_voyelles():\n assert nb_voyelles(\"bonjour\") == 3\n assert nb_voyelles(\"fdjgdhk\") == 0\n assert nb_voyelles(\"au\") == 2\n print(\"tests ok\")\n
def nb_voyelles(mot):\n voyelles = 'aeiouy'\n nb = 0\n for lettre in mot:\n if lettre in voyelles:\n nb += 1\n return nb\n
Exercice 5
\u00c9nonc\u00e9Tester sa fonctionCorrectionD\u00e9finissez une fonction decale(lettre)
qui d\u00e9cale de 3 rangs dans l'alphabet la lettre majuscule lettre
pass\u00e9e en argument (apr\u00e8s Z, on recommencera \u00e0 A..)
Aide
>>> ord('A')\n65\n>>> chr(65)\n'A'\n
Exemple d'utilisation
>>> decale('F')\n'I'\n
Vous pouvez utiliser la fonction de tests ci-dessous :
def test_decale():\n assert decale('A') == 'D'\n assert decale('Z') == 'C'\n print('tests ok !')\n
def decale(lettre):\n rang_lettre = ord(lettre)\n rang_nouvelle_lettre = rang_lettre + 3\n if rang_nouvelle_lettre > ord('Z'):\n rang_nouvelle_lettre -= 26\n nouvelle_lettre = chr(rang_nouvelle_lettre) \n\n return nouvelle_lettre\n
ou mieux, en utilisant le modulo %
: def decale(lettre):\n rang_ancienne_lettre = ord(lettre) - 65\n rang_nouvelle_lettre = (rang_ancienne_lettre + 3) % 26 + 65 \n nouvelle_lettre = chr(rang_nouvelle_lettre)\n\n return nouvelle_lettre\n
Exercice 6
\u00c9nonc\u00e9Tester sa fonctionCorrectionRajoutez un param\u00e8tre n
\u00e0 la fonction pr\u00e9c\u00e9dente pour pouvoir d\u00e9caler la lettre de n
rangs.
Exemple d'utilisation
>>> decale('B', 5)\n'G'\n
Vous pouvez utiliser la fonction de tests ci-dessous :
def test_decale():\n assert decale('A', 3) == 'D'\n assert decale('A', 5) == 'F'\n assert decale('Z', 1) == 'A'\n print('tests ok !')\n
def decale(lettre, n):\n rang_lettre = ord(lettre)\n rang_nouvelle_lettre = rang_lettre + n\n if rang_nouvelle_lettre > ord('Z'):\n rang_nouvelle_lettre -= 26\n nouvelle_lettre = chr(rang_nouvelle_lettre) \n\n return nouvelle_lettre\n
Exercice 7
\u00c9nonc\u00e9CorrectionUtilisez la fonction pr\u00e9c\u00e9dente pour cr\u00e9er la fonction decale_phrase(p, n)
qui d\u00e9cale toutes les lettres d'une phrase p
de n
rangs. On laissera les espaces intacts.
Exemple d'utilisation
>>> decale_phrase(\"PAS MAL DU TOUT\", 4)\n'TEW QEP HY XSYX'\n
def decale_phrase(p, n):\n phrase_decalee = ''\n for lettre in p:\n if lettre == ' ':\n phrase_decalee += ' '\n else:\n nouvelle_lettre = decale(lettre, n)\n phrase_decalee += nouvelle_lettre\n return phrase_decalee\n
Exercice 8
\u00c9nonc\u00e9CorrectionD\u00e9codez la phrase RT BTHHPVT CT RDCIXTCI GXTC S XCITGTHHPCI
.
def decale(lettre, n):\n rang_lettre = ord(lettre)\n rang_nouvelle_lettre = rang_lettre + n\n if rang_nouvelle_lettre > ord('Z'):\n rang_nouvelle_lettre -= 26\n nouvelle_lettre = chr(rang_nouvelle_lettre) \n\n return nouvelle_lettre\n\ndef decale_phrase(p, n):\n phrase_decalee = ''\n for lettre in p:\n if lettre == ' ':\n phrase_decalee += ' '\n else:\n nouvelle_lettre = decale(lettre, n)\n phrase_decalee += nouvelle_lettre\n return phrase_decalee\n\n\ndef decrypt(msg_secret):\n for decalage in range(25):\n print(decale_phrase(msg_secret, decalage))\n\nmsg = 'RT BTHHPVT CT RDCIXTCI GXTC S XCITGTHHPCI'\n\ndecrypt(msg)\n\n# cette m\u00e9thode impose de tout lire pour y chercher une phrase ayant du sens.\n# Si on sait que la phrase sera en fran\u00e7ais, on peut chercher des mots du\n# dictionnaire. Si par exemple on sait que la phrase contiendra le mot 'MESSAGE',\n# le code peut devenir :\n\n\ndef decrypt2(msg_secret):\n for decalage in range(25):\n phrase_clair = decale_phrase(msg_secret, decalage)\n if 'MESSAGE' in phrase_clair:\n print(phrase_clair)\n\nmsg = 'RT BTHHPVT CT RDCIXTCI GXTC S XCITGTHHPCI'\n\ndecrypt2(msg)\n
Exercice 9
\u00c9nonc\u00e9CorrectionLa conjecture de Syracuse (ou de Collatz) postule ceci :
Prenons un nombre \\(n\\) : si \\(n\\) est pair, on le divise par 2, sinon on le multiplie par 3 puis on ajoute 1. On recommence cette op\u00e9ration tant que possible. Au bout d'un certain temps, on finira toujours par tomber sur le nombre 1.
suivant(n)
qui renvoie le successeur du nombre n
, suivant les r\u00e8gles \u00e9nonc\u00e9es ci-dessus.syracuse(n)
qui affiche tous les termes de la suite de Syracuse jusqu'\u00e0 (on l'esp\u00e8re !) 1. 1.
def suivant(n):\n if n % 2 == 0:\n return n // 2\n else:\n return 3*n + 1\n
2. def syracuse(n):\n print(n)\n while n != 1:\n n = suivant(n)\n print(n)\n
Exercice 10
\u00c9nonc\u00e9Correctiontemps_de_vol(n)
qui renvoie le nombre d'\u00e9tapes pour arriver \u00e0 1, en partant de n
temps_max(nmax)
qui affiche le plus grand temps de vol pour un nombre entre 1 et nmax
.1.
def temps_de_vol(n):\n compteur = 1\n while n != 1:\n compteur += 1\n n = suivant(n)\n return compteur\n
2. def temps_max(nmax):\n maximum = 0\n for k in range(1, nmax + 1):\n duree = temps_de_vol(k)\n if duree > maximum:\n maximum = duree\n print('le plus grand temps de vol vaut :', maximum)\n
"},{"location":"T2_Representation_des_donnees/sommaire/","title":"Th\u00e8me 2 : Repr\u00e9sentation des donn\u00e9es","text":"Les listes font partie de ce qu'on appelle les donn\u00e9es composites (nous verrons plus tard les tuples et les dictionnaires). Elles permettent de regrouper de mani\u00e8re structur\u00e9e un ensemble de valeurs (et non plus une valeur unique). On les appelle listes en Python, ou bien tableaux de mani\u00e8re plus g\u00e9n\u00e9rale.
"},{"location":"T2_Representation_des_donnees/2.1_Listes/cours/#1-declaration-dune-liste","title":"1. D\u00e9claration d'une liste","text":"Exemple fondateur n\u00b01
Une variable de type liste sera d\u00e9limit\u00e9e par des crochets, et ses \u00e9l\u00e9ments s\u00e9par\u00e9s par des virgules :
>>> maliste = [\"riri\", \"fifi\", \"loulou\"]\n
On peut observer le type de la variable ainsi cr\u00e9\u00e9e :
>>> type(maliste)\n<class 'list'>\n
Remarques :
M\u00eame si cela n'a ici un grand int\u00e9r\u00eat, les \u00e9l\u00e9ments d'une liste peuvent donc \u00eatre de types diff\u00e9rents : ici, tous les \u00e9l\u00e9ments de ma liste sont des cha\u00eenes de caract\u00e8res (str
), mais la liste [\"riri\", 5, \"fifi\", \"loulou\"]
est aussi une liste valide.
Une liste vide se d\u00e9clarera avec []
.
>>> copies_corrigees = []\n
Nous verrons plus tard qu'il est fr\u00e9quent dans les exercices de partir d'une liste vide et d'ajouter progressivement des \u00e9l\u00e9ments. Exemple fondateur n\u00b02
On acc\u00e8de \u00e0 un \u00e9l\u00e9ment d'une liste en mettant entre crochets l'indice de l'\u00e9l\u00e9ment (qui commence \u00e0 z\u00e9ro).
>>> famille = [\"Bart\", \"Lisa\", \"Maggie\"] # (1)\n>>> famille[0]\n'Bart'\n>>> famille[1]\n'Lisa'\n>>> famille[2]\n'Maggie'\n>>> famille[3]\nTraceback (most recent call last):\n File \"<pyshell>\", line 1, in <module>\nIndexError: list index out of range\n
Remarques :
Un indice qui d\u00e9passe la valeur \u00a0longueur de la liste -1
provoquera donc une erreur list index out of range
. C'est une erreur tr\u00e8s fr\u00e9quente lorsqu'on manipule des listes.
Il est par contre possible d'utiliser des indices n\u00e9gatifs. On utilise par exemple tr\u00e8s souvent l'indice -1 pour acc\u00e9der au dernier \u00e9l\u00e9ment de la liste, sans avoir \u00e0 conna\u00eetre la longueur de celle-ci :
>>> famille[-1]\n'Maggie'\n
"},{"location":"T2_Representation_des_donnees/2.1_Listes/cours/#3-longueur-dune-liste","title":"3. Longueur d'une liste","text":"Exemple fondateur n\u00b03
La longueur d'une liste sera donn\u00e9e par la fonction len()
, qui renvoie donc un nombre entier positif ou nul.
>>> len(famille)\n3\n
Remarques :
>>> len([])\n0\n
maliste
(non vide) sera donc toujours l'\u00e9l\u00e9ment d'indice len(maliste)-1
. >>> famille[len(famille) - 1]\n'Maggie'\n
Il existe deux m\u00e9thodes pour parcourir s\u00e9quentiellement tous les \u00e9l\u00e9ments d'une liste. Ces deux m\u00e9thodes sont \u00e0 ma\u00eetriser imp\u00e9rativement.
"},{"location":"T2_Representation_des_donnees/2.1_Listes/cours/#41-parcours-par-elements","title":"4.1 Parcours \u00abpar \u00e9l\u00e9ments\u00bb","text":"C'est la m\u00e9thode la plus naturelle, celle d\u00e9j\u00e0 vue lors de la pr\u00e9sentation de la boucle for
. Nous allons simplement it\u00e9rer sur les \u00e9l\u00e9ments de la liste.
Exemple fondateur n\u00b04
Le code :
famille = [\"Bart\", \"Lisa\", \"Maggie\"]\n\nfor membre in famille:\n print(membre)\n
renverra : Bart\nLisa\nMaggie\n
Remarque :
for k in famille:\n print(k)\n
En effet le nom de variable k
est habituellement utilis\u00e9 pour les nombres (les indices, les compteurs...).Exercice 1
\u00c9nonc\u00e9CorrectionApr\u00e8s un r\u00e9f\u00e9rendum, la liste urne
contient uniquement des 'oui'
ou des 'non'
. D\u00e9terminer le vainqueur de ce r\u00e9f\u00e9rendum.
urne = ['oui', 'non', 'non', 'oui', 'oui', 'oui', 'non', 'oui', 'oui', 'oui', 'non', 'oui', 'non', 'non', 'oui', 'non', 'non', 'oui', 'oui', 'oui', 'oui', 'non', 'non', 'oui', 'non', 'oui', 'non', 'non', 'non', 'oui', 'oui', 'oui', 'oui', 'non', 'oui', 'non', 'non', 'oui', 'non', 'non', 'oui', 'non', 'non', 'non', 'non', 'non', 'non', 'non', 'oui', 'non', 'non', 'oui', 'oui', 'non', 'oui', 'oui', 'oui', 'oui', 'oui', 'oui', 'non', 'non', 'oui', 'oui', 'oui', 'oui', 'non', 'non', 'non', 'oui', 'oui', 'oui', 'non', 'non', 'non', 'non', 'oui', 'non', 'non', 'non', 'non', 'non', 'non', 'non', 'non', 'oui', 'non', 'oui', 'non', 'non', 'oui', 'oui', 'non', 'non', 'non', 'oui', 'oui', 'non', 'oui', 'oui', 'non', 'non', 'oui', 'oui', 'oui', 'non', 'oui', 'non', 'oui', 'oui', 'oui', 'oui', 'oui', 'non', 'non', 'non', 'non', 'oui', 'oui', 'oui', 'non', 'oui', 'non', 'oui', 'oui', 'oui', 'oui', 'oui', 'non', 'non', 'oui', 'non', 'non', 'non', 'non', 'non', 'non', 'oui', 'non', 'non', 'oui', 'non', 'non', 'oui', 'non', 'non', 'oui', 'oui', 'oui', 'oui', 'oui', 'oui', 'non', 'oui']\n
urne = ['oui', 'non', 'non', 'oui', 'oui', 'oui', 'non', 'oui', 'oui', 'oui', 'non', 'oui', 'non', 'non', 'oui', 'non', 'non', 'oui', 'oui', 'oui', 'oui', 'non', 'non', 'oui', 'non', 'oui', 'non', 'non', 'non', 'oui', 'oui', 'oui', 'oui', 'non', 'oui', 'non', 'non', 'oui', 'non', 'non', 'oui', 'non', 'non', 'non', 'non', 'non', 'non', 'non', 'oui', 'non', 'non', 'oui', 'oui', 'non', 'oui', 'oui', 'oui', 'oui', 'oui', 'oui', 'non', 'non', 'oui', 'oui', 'oui', 'oui', 'non', 'non', 'non', 'oui', 'oui', 'oui', 'non', 'non', 'non', 'non', 'oui', 'non', 'non', 'non', 'non', 'non', 'non', 'non', 'non', 'oui', 'non', 'oui', 'non', 'non', 'oui', 'oui', 'non', 'non', 'non', 'oui', 'oui', 'non', 'oui', 'oui', 'non', 'non', 'oui', 'oui', 'oui', 'non', 'oui', 'non', 'oui', 'oui', 'oui', 'oui', 'oui', 'non', 'non', 'non', 'non', 'oui', 'oui', 'oui', 'non', 'oui', 'non', 'oui', 'oui', 'oui', 'oui', 'oui', 'non', 'non', 'oui', 'non', 'non', 'non', 'non', 'non', 'non', 'oui', 'non', 'non', 'oui', 'non', 'non', 'oui', 'non', 'non', 'oui', 'oui', 'oui', 'oui', 'oui', 'oui', 'non', 'oui']\n\nnb_oui = 0\nnb_non = 0\nfor vote in urne:\n if vote == 'oui':\n nb_oui += 1\n else:\n nb_non += 1\nprint('pourcentage de oui', 100*nb_oui/len(urne), '%')\nprint('pourcentage de non', 100*nb_non/len(urne), '%')\nprint('-'*10)\nif nb_oui > nb_non:\n print('le oui est vainqueur')\nelif nb_oui < nb_non:\n print('le non est vainqueur')\nelse:\n print('le oui et le non sont \u00e0 \u00e9galit\u00e9')\n
"},{"location":"T2_Representation_des_donnees/2.1_Listes/cours/#42-parcours-par-indice","title":"4.2 Parcours \u00abpar indice\u00bb","text":"Chaque \u00e9l\u00e9ment \u00e9tant accessible par son indice (de 0
\u00e0 len(liste) - 1
), il suffit de faire parcourir \u00e0 une variable i
l'ensemble des entiers de 0
\u00e0 len(liste) - 1
, par l'instruction range(len(liste))
:
Exemple fondateur n\u00b05
Le code :
famille = [\"Bart\", \"Lisa\", \"Maggie\"]\n\nfor i in range(len(famille)):\n print(famille[i])\n
renverra : Bart\nLisa\nMaggie\n
Bonne habitude \u00e0 prendre : nommer sa variable d'indice i
, j
, k
ou indice
mais pas autre chose !
for membre in famille:\n print(membre)\n
Les avantages
index out of range
!Les inconv\u00e9nients
>>> lst = [1, 2, 3]\n>>> for nb in lst:\n nb = nb * 2 # (1)\n\n>>> lst \n[1, 2, 3] # (2)\n
lst
n'a pas chang\u00e9... for i in range(len(famille)):\n print(famille[i])\n
Les avantages
Les inconv\u00e9nients
len()
)index out of range
...Exercice 1
\u00c9nonc\u00e9CorrectionOn donne la liste :
lst = [3, 1, 4, 1, 5, 9]\n
En utilisant un parcours par indice : for i in range(len(lst)):\n print(lst[i])\n
2.
lst = [3, 1, 4, 1, 5, 9]\n\nfor i in range(len(lst)-1, -1, -1):\n print(lst[i])\n
Exercice 2
\u00c9nonc\u00e9Correction 1.Correction 2.Trouvez le nombre qui est exactement \u00e0 la m\u00eame place dans la liste list1
et dans la liste list2
, sachant que les deux listes ont la m\u00eame taille.
for
(une seule !). while
. Quel est l'avantage de la boucle while
? list1 = [8468, 4560, 3941, 3328, 7, 9910, 9208, 8400, 6502, 1076, 5921, 6720, 948, 9561, 7391, 7745, 9007, 9707, 4370, 9636, 5265, 2638, 8919, 7814, 5142, 1060, 6971, 4065, 4629, 4490, 2480, 9180, 5623, 6600, 1764, 9846, 7605, 8271, 4681, 2818, 832, 5280, 3170, 8965, 4332, 3198, 9454, 2025, 2373, 4067]\nlist2 = [9093, 2559, 9664, 8075, 4525, 5847, 67, 8932, 5049, 5241, 5886, 1393, 9413, 8872, 2560, 4636, 9004, 7586, 1461, 350, 2627, 2187, 7778, 8933, 351, 7097, 356, 4110, 1393, 4864, 1088, 3904, 5623, 8040, 7273, 1114, 4394, 4108, 7123, 8001, 5715, 7215, 7460, 5829, 9513, 1256, 4052, 1585, 1608, 3941]\n
Exercice 3
\u00c9nonc\u00e9CorrectionDans la liste
lst = [2428970, 1518306, 4971405, 1690994, 7918102, 4030834, 8830131, 7514856, 7903128, 6307569, 6624056, 5260490, 6447835, 4598783, 9108626, 5045240, 4128269, 4460134, 2497873, 5076659, 8104003, 7604887, 7451976, 4136924, 5691945, 8726293, 7855592, 3562473, 8849129, 6488474, 5303587, 2606124, 5484044, 4559758, 7592232, 2211406, 9974334, 7988936, 7582946, 7668748, 1799997, 3837917, 3196209, 7064342, 2543765, 1182013, 7253381, 1153735, 1037391, 4375946, 4445821, 5965587, 6001887, 4162629, 5235783, 8716582, 4901175, 5445422, 1120005, 8332321, 7075046, 2194175, 5557300, 2887907, 5103214, 2520744, 5104399, 2065665, 3035703, 7890213, 1758301, 3407982, 1355453, 4896338, 7979392, 9671602, 9690721, 7423779, 7423780, 3080825, 6785783, 3836837, 7310931, 1857470, 3492507, 2823231, 1492310, 1911148, 9620515, 5564910, 7009452, 7464745, 9608747, 7267383, 6939140, 6556578, 3592267, 8135497, 4881660, 5346884, 6859150]\n
se cachent deux nombres cons\u00e9cutifs. Pouvez-vous les trouver ?"},{"location":"T2_Representation_des_donnees/2.1_Listes/cours/#5-modification-dune-liste","title":"5. Modification d'une liste","text":"En Python, les objets de type List
sont modifiables (on emploie le mot mutables). Et c'est souvent une bonne chose, car des listes peuvent \u00e9voluer apr\u00e8s leur cr\u00e9ation. Lorsqu'on souhaitera figer le contenu d'une liste (pour des raisons de s\u00e9curit\u00e9 du code essentiellement), on utilisera alors le type Tuple
, qui sera vu ult\u00e9rieurement.
Il suffit d'\u00e9craser la valeur actuelle avec une nouvelle valeur
Exemple fondateur n\u00b06
>>> famille = [\"Bart\", \"Lisa\", \"Maggie\"]\n>>> famille[0] = \"Bartholomew\" # oui, c'est son vrai nom\n>>> famille\n['Bartholomew', 'Lisa', 'Maggie'] \n
"},{"location":"T2_Representation_des_donnees/2.1_Listes/cours/#52-ajout-dun-element-a-la-fin-dune-liste-la-methode-append","title":"5.2 Ajout d'un \u00e9lement \u00e0 la fin d'une liste : la m\u00e9thode append()","text":"Exemple fondateur n\u00b07
>>> famille = [\"Bart\", \"Lisa\", \"Maggie\"]\n>>> famille.append(\"Milhouse\")\n>>> famille\n['Bart', 'Lisa', 'Maggie', 'Milhouse'] \n
Remarques :
append()
rajoute donc un \u00e9l\u00e9ment \u00e0 la fin de la liste.[]
que l'on remplit peu \u00e0 peu avec des append()
.i
avec la m\u00e9thode insert
: >>> famille = [\"Bart\", \"Lisa\", \"Maggie\"]\n>>> famille.insert(1, \"Nelson\") # on ins\u00e8re \u00e0 la position 1\n>>> famille\n['Bart', 'Nelson', 'Lisa', 'Maggie']\n
Exercice 4
\u00c9nonc\u00e9CorrectionConstruire une liste contenant tous les nombres inf\u00e9rieurs \u00e0 100 qui sont divisibles par 7.
Exercice 5
\u00c9nonc\u00e9CorrectionOn consid\u00e8re la liste temp = [4, -5, 8, 10, -1, -2, 7, 13]
. Construire la liste temp_pos
qui ne contient que les \u00e9l\u00e9ments positifs de temp
.
Exemple fondateur n\u00b07
>>> famille = ['Bart', 'Nelson', 'Lisa', 'Maggie']\n>>> famille.remove(\"Nelson\")\n>>> famille\n['Bart', 'Lisa', 'Maggie']\n
Remarques :
remove
n'enl\u00e8ve que la premi\u00e8re occurrence de l'\u00e9l\u00e9ment d\u00e9sign\u00e9. S'il y en a d'autres apr\u00e8s, elles resteront dans la liste : >>> lst = [3, 1, 4, 5, 1, 9, 4]\n>>> lst.remove(4)\n>>> lst\n[3, 1, 5, 1, 9, 4]\n
>>> lst = [3, 1, 4, 5, 1, 9]\n>>> lst.remove(2)\nTraceback (most recent call last):\n File \"<pyshell>\", line 1, in <module>\nValueError: list.remove(x): x not in list\n
del
","text":"L'instruction del
(qui n'est pas une fonction) permet de supprimer un \u00e9l\u00e9ment en donnant son indice.
>>> maliste = [8, 4, 2, 5, 7]\n>>> del maliste[3]\n>>> maliste\n[8, 4, 2, 7]\n
Exercice 6
\u00c9nonc\u00e9Exercice de la BNS.
"},{"location":"T2_Representation_des_donnees/2.1_Listes/cours/#6-construction-dune-liste-delements-identiques","title":"6. Construction d'une liste d'\u00e9l\u00e9ments identiques","text":"Il est souvent pratique d'initialiser une liste de taille donn\u00e9e, souvent en la remplissant de 0.
Imaginons par exemple que nous souhaitions une liste de taille 26 remplie de 0. Il est possible de faire comme ceci :
lst = []\nfor _ in range(26):\n lst.append(0)\n
mais on pr\u00e9f\u00e8rera ce code :
Exemple fondateur n\u00b08
>>> lst = [0]*26\n
qui produira la liste [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
Exercice 7
\u00c9nonc\u00e9CorrectionQue fait le code ci-dessous ?
texte = \"cet texte est prodigieusement ennuyeux\"\n\ndef rang(lettre):\n return(ord(lettre) - 97)\n\ncompt = [0]*26\nfor lettre in texte :\n if lettre != \" \" :\n compt[rang(lettre)] += 1\n
"},{"location":"T2_Representation_des_donnees/2.1_Listes/cours/#7-construction-dune-liste-en-comprehension","title":"7. Construction d'une liste en compr\u00e9hension","text":"C'est une grande caract\u00e9ristique du langage Python (m\u00eame si ce n'est pas une exclusivit\u00e9) : la m\u00e9thode de liste en compr\u00e9hension propose une mani\u00e8re \u00e9l\u00e9gante, rapide et naturelle pour cr\u00e9er des listes.
"},{"location":"T2_Representation_des_donnees/2.1_Listes/cours/#71-en-comprehension-pourquoi","title":"7.1 \u00aben compr\u00e9hension\u00bb, pourquoi ?","text":"Cette expression vient des math\u00e9matiques. On dit qu'on d\u00e9finit un sous-ensemble par compr\u00e9hension lorsqu'on part d'un ensemble plus grand dont on ne garde que les \u00e9l\u00e9ments v\u00e9rifiant une certaine propri\u00e9t\u00e9.
On pourrait par exemple d\u00e9finir les \u00e9l\u00e8ves de Premi\u00e8re NSI de cette mani\u00e8re :
\u00ab\u00e9l\u00e8ves du lyc\u00e9e inscrits en classe de Premi\u00e8re ayant choisi la sp\u00e9cialit\u00e9 NSI\u00bb
On part d'un ensemble large (les \u00e9l\u00e8ves du lyc\u00e9e) qu'on va ensuite r\u00e9duire par des caract\u00e9risations sp\u00e9cifiques : \u00eatre un \u00e9l\u00e8ve de Premi\u00e8re, puis avoir choisi la sp\u00e9cialit\u00e9 NSI.
"},{"location":"T2_Representation_des_donnees/2.1_Listes/cours/#72-premier-exemple","title":"7.2 Premier exemple","text":"Exemple fondateur n\u00b09
Imaginons que nous poss\u00e9dons une liste data
de temp\u00e9ratures, dont nous ne voulons garder que celles strictement sup\u00e9rieures \u00e0 20.
>>> data = [17, 22, 15, 28, 16, 13, 21, 23]\n>>> good = [t for t in data if t > 20]\n>>> good\n[22, 28, 21, 23]\n
Explications :
"},{"location":"T2_Representation_des_donnees/2.1_Listes/cours/#721-le-filtre-eventuel","title":"7.2.1 le filtre \u00e9ventuel","text":"C'est lui qui donne tout son sens \u00e0 cette m\u00e9thode : il permet de ne garder que certaines valeurs. Il est pourtant \u00e9ventuel : que se passe-t-il s'il n'y a pas de filtre ?
>>> data = [17, 22, 15, 28, 16, 13, 21, 23]\n>>> good = [t for t in data]\n>>> good\n[17, 22, 15, 28, 16, 13, 21, 23]\n
On se retrouve \u00e9videmment avec une nouvelle liste qui contient exactement les \u00e9l\u00e9ments de la liste de d\u00e9part, ce qui n'est pas tr\u00e8s int\u00e9ressant. Pourtant les listes en compr\u00e9hension sans filtre sont tr\u00e8s fr\u00e9quentes, nous le verrons plus loin. Exercice 8
\u00c9nonc\u00e9CorrectionOn consid\u00e8re la variable phrase = 'Bonjour les vacances sont finies'
et la variable voyelles = 'aeiouy'
.
Construire en compr\u00e9hension la liste liste_voyelles
qui contient toutes les voyelles pr\u00e9sentes dans la variable phrase
.
C'est \u00e0 partir de lui que va se construire notre liste. Pour l'instant, cet ensemble de d\u00e9part a toujours \u00e9t\u00e9 de type list
.
Cet ensemble peut \u00eatre aussi donn\u00e9 \u00e0 partir de l'instruction range()
. Souvenons-nous de l'exercice 4 : \u00abConstruire une liste contenant tous les nombres inf\u00e9rieurs \u00e0 100 qui sont divisibles par 7.\u00bb.
Une solution possible \u00e9tait :
lst = []\nfor n in range(1, 101):\n if n % 7 == 0:\n lst.append(n)\n
Ce code peut maintenant s'\u00e9crire tr\u00e8s simplement en une seule instruction :
Exemple fondateur n\u00b010
>>> lst = [n for n in range(1,101) if n % 7 == 0]\n>>> lst\n[7, 14, 21, 28, 35, 42, 49, 56, 63, 70, 77, 84, 91, 98]\n
"},{"location":"T2_Representation_des_donnees/2.1_Listes/cours/#723-la-valeur-a-garder","title":"7.2.3 la valeur \u00e0 garder","text":"Pour l'instant, nous avons proc\u00e9d\u00e9 \u00e0 des filtres sur des ensembles existants, sans modifier la valeur filtr\u00e9e (la valeur \u00e0 garder). Les listes en compr\u00e9hension deviennent encore plus int\u00e9ressantes lorsqu'on comprend qu'il est possible de modifier la valeur filtr\u00e9e :
Exemple fondateur n\u00b011
>>> lst_carres = [t**2 for t in range(1,10)]\n>>> lst_carres\n[1, 4, 9, 16, 25, 36, 49, 64, 81]\n
Exercice 9
\u00c9nonc\u00e9Correctionf
.Exercice 10
\u00c9nonc\u00e9CorrectionOn consid\u00e8re la liste lst = [51, 52, 66, 91, 92, 82, 65, 53, 86, 42, 79, 95]
. Seuls les nombres entre 60 et 90 ont une signification : ce sont des codes ASCII (r\u00e9cup\u00e9rables par la fonction chr
). Cr\u00e9er (en compr\u00e9hension) une liste sol
qui contient les lettres correspondants aux nombres ayant une signification.
une copie un peu trop parfaite
Observez le code ci-dessous, r\u00e9alis\u00e9 sans trucage.
>>> listA = [1, 2, 3]\n>>> listB = listA\n>>> listA.append(7)\n>>> listB\n[1, 2, 3, 7]\n>>> listB.append(8)\n>>> listA\n[1, 2, 3, 7, 8]\n
Tout se passe comme si les listes listA
etlistB
\u00e9taient devenus des clones \u00absynchronis\u00e9s\u00bb depuis l'affectation listB = listA
.
Analyse gr\u00e2ce \u00e0 PythonTutor
L'illustration de PythonTutor nous donne la cl\u00e9 de l'\u00e9nigme :
listA
etlistB
sont en fait un seul et m\u00eame objet.
Comment en avoir le c\u0153ur net ? En observant leur adresse-m\u00e9moire, disponible gr\u00e2ce \u00e0 la fonction id
:
>>> id(listA)\n140485841327616\n>>> id(listB)\n140485841327616\n
Ceci met en \u00e9vidence que la m\u00e9taphore du tiroir dont on se sert pour expliquer ce qu'est une variable est malheureusement inexacte. Une variable est une r\u00e9f\u00e9rence vers une adresse-m\u00e9moire. Si deux variables font r\u00e9f\u00e9rence \u00e0 la m\u00eame adresse-m\u00e9moire, alors elles sont totalement identiques: toute modification de l'une entra\u00eene une modification de l'autre.
Pour en savoir plus sur les variables, vous pouvez revenir sur la partie optionnelle du cours sur les variables.
"},{"location":"T2_Representation_des_donnees/2.1_Listes/cours/#mais-alors-comment-copier-le-contenu-dune-liste-vers-une-autre-sans-creer-un-clone","title":"Mais alors, comment copier le contenu d'une liste vers une autre sans cr\u00e9er un clone ?","text":"Exemple fondateur n\u00b012
>>> listA = [3, 4, 5]\n>>> listB = list(listA)\n
D'autres possibilit\u00e9s existent, comme listA.copy()
, ou encore listA[::]
... Exercice 11
\u00c9nonc\u00e9CorrectionEffectuer les tests n\u00e9cessaires pour prouver que l'exemple pr\u00e9c\u00e9dent a bien produit deux objets diff\u00e9rents.
"},{"location":"T2_Representation_des_donnees/2.1_Listes/cours/#9-tableaux-a-plusieurs-dimensions-listes-de-listes","title":"9. Tableaux \u00e0 plusieurs dimensions : listes de listes","text":"Nous avons vu qu'une liste pouvait contenir des \u00e9l\u00e9ments de tous types : des entiers, des chaines des caract\u00e8res... et pourquoi pas une liste qui contient des listes ?
"},{"location":"T2_Representation_des_donnees/2.1_Listes/cours/#91-syntaxe","title":"9.1 Syntaxe","text":"Exemple fondateur n\u00b012
La liste tab
ci-dessous est compos\u00e9e de 3 listes qui elles-m\u00eames contiennent trois nombres :
tab = [[3, 5, 2],\n [7, 1, 4], \n [8, 6, 9]]\n
tab[0][0] = 3
tab[0][1] = 5
tab[2][1] = 6
tab[1] = [7, 1, 4]
La liste a
est compos\u00e9e de 3 \u00e9l\u00e9ments qui sont eux-m\u00eame des listes de 3 \u00e9l\u00e9ments.
Exercice 12
\u00c9nonc\u00e9CorrectionOn consid\u00e8re le jeu du Morpion (ou Tic-Tac-Toe) dont la surface de jeu vierge est represent\u00e9e par le tableau : tab = [[' ', ' ', ' '], [' ', ' ', ' '], [' ', ' ', ' ']]
Les premiers coups jou\u00e9s sont ceux-ci :
tab[1][1] = 'X'
tab[2][1] = 'O'
tab[2][2] = 'X'
tab[0][0] = 'O'
Quel coup doit maintenant jouer le joueur 'X'
pour s'assurer la victoire ?
Exemple fondateur n\u00b013
Parcours par \u00e9l\u00e9ments :
for ligne in tab:\n for elt in ligne:\n print(elt)\n
Parcours par indice :
for i in range(3):\n for j in range(3):\n print(tab[i][j])\n
Exercice 13
\u00c9nonc\u00e9CorrectionOn consid\u00e8re la liste m
('m' comme matrice) suivante :
m = [[1, 9, 4], [4, 1, 8], [7, 10, 1]]
Quelle est la somme de tous les nombres de la matrice m
?
Exercice 1
\u00c9nonc\u00e9CorrectionR\u00e9solvez le Pyd\u00e9fi propos\u00e9 \u00e0 cette adresse
Vous pouvez vous cr\u00e9er un compte pour valider vos r\u00e9sultats, ce site (g\u00e9r\u00e9 par l'Acad\u00e9mie de Poitiers) est remarquable.
(avec les valeurs de test)
lst = [0, 50, 40, 100, 70, 90, 0]\n\ntotal = 0\nfor i in range(len(lst)-1):\n if lst[i] > lst[i+1]:\n nb_pierres = (lst[i]-lst[i+1])//10 + 1\n total += nb_pierres\n\nprint(total)\n
Exercice 2
\u00c9nonc\u00e9CorrectionOn donne la liste jours
suivante :
jours = [\"lundi\", \"mardi\", \"mercredi\", \"jeudi\", \"vendredi\", \"samedi\", \"dimanche\"]\n
On rappelle que la fonction len
permet d'obtenir le nombre de caract\u00e8res d'une chaine de caract\u00e8res :
>>> len(\"test\")\n4\n
lst1
contenant uniquement les jours comportant 5 lettres.lst2
contenant uniquement les jours comportant la lettre a
dans leur nom.compte_e
qui prend en param\u00e8tre une chaine de caract\u00e8res et qui renvoie le nombre de e
que contient cette chaine de caract\u00e8res.lst4
contenant uniquement les jours comportant deux fois la lettre e
dans leur nom.1.
lst1 = [day for day in jours if len(day) == 5]\n
2. lst2 = [day for day in jours if 'a' in day]\n
def compte_e(mot):\n compteur = 0\n for lettre in mot:\n if lettre == 'e':\n compteur += 1\n return compteur\n
lst4 = [day for day in jours if compte_e(day) == 2]\n
Exercice 3
\u00c9nonc\u00e9CorrectionOn donne le tableau m
suivant :
m = [[17, 71, 75, 89, 45, 10, 54, 26, 59, 47, 57, 64, 44], \\\n [67, 25, 47, 49, 28, 40, 10, 17, 77, 35, 87, 15, 68], \\\n [66, 89, 28, 43, 16, 14, 12, 21, 68, 22, 14, 18, 59], \\\n [60, 35, 30, 23, 22, 37, 49, 89, 82, 80, 85, 28, 17], \\\n [61, 42, 39, 46, 29, 38, 85, 72, 44, 60, 47, 35, 52], \\\n [44, 28, 24, 40, 71, 71, 46, 25, 78, 54, 66, 84, 52], \\\n [29, 71, 7, 38, 71, 60, 71, 60, 16, 82, 35, 39, 23], \\\n [18, 61, 38, 7, 8, 32, 67, 43, 23, 28, 29, 16, 30], \\\n [45, 30, 74, 9, 84, 78, 11, 80, 42, 64, 9, 39, 26], \\\n [78, 57, 54, 66, 57, 63, 10, 42, 61, 19, 26, 25, 53], \\\n [38, 87, 10, 64, 75, 26, 14, 68, 19, 33, 75, 50, 18], \\\n [52, 81, 24, 67, 37, 78, 17, 19, 61, 82, 57, 24, 54]]\n
Afficher successivement chaque ligne du tableau en respectant les r\u00e8gles suivantes : *
, sinon afficher une espace
end = ''
\u00e0 la fonction print
. (exemple : print('*', end = '')
)print()
m = [[17, 71, 75, 89, 45, 10, 54, 26, 59, 47, 57, 64, 44], \\\n [67, 25, 47, 49, 28, 40, 10, 17, 77, 35, 87, 15, 68], \\\n [66, 89, 28, 43, 16, 14, 12, 21, 68, 22, 14, 18, 59], \\\n [60, 35, 30, 23, 22, 37, 49, 89, 82, 80, 85, 28, 17], \\\n [61, 42, 39, 46, 29, 38, 85, 72, 44, 60, 47, 35, 52], \\\n [44, 28, 24, 40, 71, 71, 46, 25, 78, 54, 66, 84, 52], \\\n [29, 71, 7, 38, 71, 60, 71, 60, 16, 82, 35, 39, 23], \\\n [18, 61, 38, 7, 8, 32, 67, 43, 23, 28, 29, 16, 30], \\\n [45, 30, 74, 9, 84, 78, 11, 80, 42, 64, 9, 39, 26], \\\n [78, 57, 54, 66, 57, 63, 10, 42, 61, 19, 26, 25, 53], \\\n [38, 87, 10, 64, 75, 26, 14, 68, 19, 33, 75, 50, 18], \\\n [52, 81, 24, 67, 37, 78, 17, 19, 61, 82, 57, 24, 54]]\n\nfor ligne in m:\n for elt in ligne:\n if elt % 7 == 0:\n print('*', end = '')\n else:\n print(' ', end = '')\n print('')\n
Exercice 4
\u00c9nonc\u00e9CorrectionR\u00e9solvez le pyd\u00e9fi Insaisissable matrice propos\u00e9 \u00e0 cette adresse
M=[[17, 3, 4, 14, 5, 17], [8, 16, 3, 17, 14, 12], [13, 5, 15, 4, 16, 3], [14, 7, 3, 16, 3, 2], [6, 1, 16, 10, 5, 13], [11, 1, 9, 11, 18, 8]]\n\ndef f(k):\n return (9*k + 3) % 19\n\nfor _ in range(39):\n for i in range(6):\n for j in range(6):\n M[i][j] = f(M[i][j])\n\nsomme = 0\nfor i in range(6):\n for j in range(6):\n somme += M[i][j]\n\nprint(somme)\n
Exercice 5
\u00c9nonc\u00e9CorrectionD'apr\u00e8s Advent Of Code 2021, day02
Un sous-marin peut se d\u00e9placer horizontalement (toujours vers la droite) gr\u00e2ce \u00e0 l'instruction forward
suivie d'un nombre.
Il peut aussi monter ou descendre, gr\u00e2ce aux instructions up
ou down
, elles aussi suivies d'un nombre.
Un grand nombre d'instructions successives sont donn\u00e9es. Le but de l'exercice est de trouver le produit final de l'abscisse du sous-marin et de sa profondeur.
Exemple :
forward 5\ndown 5\nforward 8\nup 3\ndown 8\nforward 2\n
Apr\u00e8s ces d\u00e9placements, le sous-marin se trouve \u00e0 l'abscisse 15 et \u00e0 la profondeur 10. La r\u00e9ponse \u00e0 l'\u00e9nigme serait donc 150.
\u00e9nonc\u00e9 orginal
T\u00e9l\u00e9chargez le fichier input1.txt. Votre fichier .py
de travail doit se situer dans le m\u00eame r\u00e9pertoire que le fichier input1.txt
.
Q1. Nous allons r\u00e9cup\u00e9rer toutes les donn\u00e9es (on dit parser les donn\u00e9es) dans une liste, gr\u00e2ce \u00e0 l'instruction :
data_str = open('input1.txt').read().splitlines()\n
Combien cette liste comporte-t-elle d'\u00e9l\u00e9ments ? Q2. Afficher successivement tous les \u00e9l\u00e9ments de cette liste.
Q3. Pour s\u00e9parer une chaine de caract\u00e8res en une liste de plusieurs chaines de caract\u00e8res, nous pouvons utiliser la fonction split
:
>>> \"hello world\".split(\" \")\n['hello', 'world']\n
Gr\u00e2ce \u00e0 cette fonction split
, affichez successivement uniquement les instructions forward
, up
ou down
. Q4. Appelons x
et y
l'abscisse et l'ordonn\u00e9e (initialis\u00e9es \u00e0 0) du sous-marin. Que valent x
et y
\u00e0 la fin des instructions ?
On rappelle que la fonction int
permet de convertir une chaine de caract\u00e8res en nombre :
>>> int('4')\n4\n
data_str = open('input1.txt').read().splitlines()\n\nfor ligne in data_str:\n lst = ligne.split(' ')\n if lst[0] == 'forward':\n x += int(lst[1])\n elif lst[0] == 'down':\n y += int(lst[1])\n else:\n y -= int(lst[1])\n\nprint(x*y)\n
"},{"location":"T2_Representation_des_donnees/2.2_Tuples/cours/","title":"2.2 Tuples","text":""},{"location":"T2_Representation_des_donnees/2.2_Tuples/cours/#1definition-des-tuples","title":"1.D\u00e9finition des tuples","text":"Les tuples (appel\u00e9s p-uplets dans le programme officiel de NSI) sont une collection d'objets ordonn\u00e9e mais NON MODIFIABLE. Pour rappel :
Quel peut \u00eatre l'int\u00e9r\u00eat d'un tuple par rapport \u00e0 une liste ?
>>> monPremierTuple = (3, 5, 6)\n
Un tuple se diff\u00e9rencie d'une liste par l'utilisation des parenth\u00e8ses au lieu des crochets.
>>> type(monPremierTuple)\ntuple\n
\u00c0 noter qu'un tuple peut \u00eatre d\u00e9clar\u00e9 sans parenth\u00e8ses. C'est toutefois \u00e0 \u00e9viter.
>>> taille = 600, 800\n>>> type(taille)\ntuple\n
"},{"location":"T2_Representation_des_donnees/2.2_Tuples/cours/#2-acces-aux-elements-dun-tuple","title":"2. Acc\u00e8s aux \u00e9l\u00e9ments d'un tuple","text":"Comme pour une liste ou une cha\u00eene de caract\u00e8re, l'acc\u00e8s se fait par un indice entre crochets.
>>> a = (12, 25, 6)\n>>> a[0]\n12\n
"},{"location":"T2_Representation_des_donnees/2.2_Tuples/cours/#3-tentative-de-modification-dun-tuple","title":"3. Tentative de modification d'un tuple","text":">>> a[0] = 4\n ---------------------------------------------------------------------------\n TypeError Traceback (most recent call last)\n\n <ipython-input-7-5fe525706b2b> in <module>()\n ----> 1 a[0] = 4\n\n\n TypeError: 'tuple' object does not support item assignment\n
"},{"location":"T2_Representation_des_donnees/2.2_Tuples/cours/#4-parcours-dun-tuple","title":"4. Parcours d'un tuple","text":"On retrouve bien \u00e9videmment les deux m\u00e9thodes utilisables pour les listes :
"},{"location":"T2_Representation_des_donnees/2.2_Tuples/cours/#41-parcours-par-indice","title":"4.1 Parcours par indice","text":">>> for k in range(len(a)):\n print(a[k])\n12\n25\n6\n
"},{"location":"T2_Representation_des_donnees/2.2_Tuples/cours/#41-parcours-par-element","title":"4.1 Parcours par \u00e9l\u00e9ment","text":">>> for k in a :\n print(k)\n12\n25\n6\n
"},{"location":"T2_Representation_des_donnees/2.2_Tuples/cours/#5-construction-dune-fonction-renvoyant-un-tuple","title":"5. Construction d'une fonction renvoyant un tuple","text":"def division(a, b):\n # fonction renvoyant le tuple (quotient, reste) de la division euclidienne de a par b.\n q = a // b\n r = a % b\n return (q, r)\n
>>> division(49,12)\n(4,1)\n
"},{"location":"T2_Representation_des_donnees/2.2_Tuples/cours/#6-exercice","title":"6. Exercice","text":"Exercice
\u00c9nonc\u00e9CorrectionOn consid\u00e8re deux points A et B d'un rep\u00e8re quelconque. Leurs coordonn\u00e9es sont des tuples \u00e0 deux \u00e9l\u00e9ments. \u00c9crire une fonction qui prend en argument les coordonn\u00e9es de deux points et qui renvoie le milieu de ces deux points.
La fonction doit fonctionner de cette mani\u00e8re :
>>> C = (45, 12)\n>>> D = (49, 32)\n>>> milieu(C,D)\n(47, 22)\n
"},{"location":"T2_Representation_des_donnees/2.3_Dictionnaires/cours/","title":"2.3 Dictionnaires","text":""},{"location":"T2_Representation_des_donnees/2.3_Dictionnaires/cours/#1-les-dictionnaires-premiers-exemples","title":"1. Les dictionnaires : premiers exemples","text":"Une liste est un ensemble d'\u00e9l\u00e9ments accessibles par leur indice. Cet indice est en quelque sorte la \u00abplace\u00bb de l'\u00e9l\u00e9ment dans la liste. On peut dire que cet indice est la cl\u00e9 qui permet d'acc\u00e9der \u00e0 l'\u00e9l\u00e9ment.
Dans un dictionnaire, chaque \u00e9l\u00e9ment est accessible par une cl\u00e9 qui n'est plus forc\u00e9ment un nombre : une chaine de caract\u00e8re, un nombre, ou autre chose, peut \u00eatre une cl\u00e9.
Imaginons que je fasse l'inventaire de mon dressing :
habits quantit\u00e9 pantalons 3 pulls 4 tee-shirts 8Exemple fondateur n\u00b01
>>> dressing = {\"pantalons\":3, \"pulls\":4, \"tee-shirts\":8}\n
>>> dressing[\"pulls\"]\n 4\n
On dit que \"pulls\"
est la cl\u00e9 et que 4 est la valeur associ\u00e9e \u00e0 la cl\u00e9.
Un dictionnaire est un ensemble cl\u00e9s / valeurs.
Attention : une cl\u00e9 peut aussi \u00eatre un nombre :
>>> myst = {9:4, 1:2, 6:3, 7:4} \n>>> myst[1]\n2\n>>> myst[7]\n4 \n
"},{"location":"T2_Representation_des_donnees/2.3_Dictionnaires/cours/#2-definitions-et-proprietes-dun-dictionnaire","title":"2. D\u00e9finitions et propri\u00e9t\u00e9s d'un dictionnaire","text":""},{"location":"T2_Representation_des_donnees/2.3_Dictionnaires/cours/#21-definitions","title":"2.1 D\u00e9finitions","text":"D\u00e9finition
Un dictionnaire est une donn\u00e9e composite qui n'est pas ordonn\u00e9e (\u00e0 la diff\u00e9rence des listes !) Il fonctionne par un syst\u00e8me de cl\u00e9:valeur
. Les cl\u00e9s, comme les valeurs, peuvent \u00eatre de types diff\u00e9rents. Un dictionnaire est d\u00e9limit\u00e9 par des accolades.
Rappel :
[ ]
-> listes( )
-> tuples{ }
-> dictionnaires.keys()
et .values()
","text":"Exemples fondateurs n\u00b02
>>> dressing.keys()\ndict_keys(['pantalons', 'pulls', 'tee-shirts'])\n
>>> dressing.values()\ndict_values([3, 4, 8])\n
Ces m\u00e9thodes sont importantes (elles figurent explicitement au programme de NSI) mais sont en pratique peu utilis\u00e9es. On leur pr\u00e9f\u00e8rera tr\u00e8s largement la m\u00e9thode de parcours suivante :
"},{"location":"T2_Representation_des_donnees/2.3_Dictionnaires/cours/#23-parcours-dun-dictionnaire","title":"2.3 Parcours d'un dictionnaire","text":"Exemple fondateur n\u00b03
>>> for habit in dressing:\n print(dressing[habit])\n3\n4\n8\n
Observation gr\u00e2ce \u00e0 PythonTutor
"},{"location":"T2_Representation_des_donnees/2.3_Dictionnaires/cours/#24-creation-dun-dictionnaire-vide","title":"2.4 Cr\u00e9ation d'un dictionnaire vide","text":"
Exemple fondateur n\u00b04
Deux m\u00e9thodes existent pour cr\u00e9er un dictionnaire : dict()
et {}
>>> mondico = dict()\n>>> mondico\n{}\n>>> mondico['john'] = 12\n>>> mondico\n{'john': 12}\n
>>> contacts = {}\n>>> contacts['bob'] = '06 12 17 21 32'\n
"},{"location":"T2_Representation_des_donnees/2.3_Dictionnaires/cours/#25-ajout-modification-dun-element-dans-un-dictionnaire","title":"2.5 Ajout / Modification d'un \u00e9l\u00e9ment dans un dictionnaire","text":"Exemple fondateur n\u00b05
Pas besoin d'une m\u00e9thode append()
, il suffit de rajouter une paire cl\u00e9 : valeur
>>> dressing[\"chaussettes\"] = 12\n
On peut aussi modifier un dictionnaire existant.
dressing[\"chaussettes\"] = 11\n
"},{"location":"T2_Representation_des_donnees/2.3_Dictionnaires/cours/#26-suppression-dune-valeur","title":"2.6 Suppression d'une valeur","text":"Exemple fondateur n\u00b06
On utilise l'instruction del
(d\u00e9j\u00e0 rencontr\u00e9e pour les listes)
del dressing[\"chaussettes\"]\n
Exercice 1
\u00c9nonc\u00e9CorrectionReprenons notre dictionnaire dressing
:
dressing = {\"pantalons\":3, \"pulls\":4, \"tee-shirts\":8}\n
Cr\u00e9er une fonction achat(habit)
qui augmente de 1 le nombre d'habits (pantalon, pull ou tee-shirt) de mon dressing. dressing = {\"pantalons\":3, \"pulls\":4, \"tee-shirts\":8}\n\ndef achat(habit):\n dressing[habit] += 1\n
Remarque : Petit probl\u00e8me si on essaie d'acheter un v\u00eatement pour la 1\u00e8re fois
>>> achat(\"chemises\")\n ---------------------------------------------------------------------------\n\n KeyError Traceback (most recent call last)\n\n <ipython-input-28-fd9d1ac5f62d> in <module>\n ----> 1 achat(\"chemises\")\n\n\n <ipython-input-27-feb173444189> in achat(habit)\n 1 def achat(habit):\n ----> 2 dressing[habit] = dressing[habit] + 1\n\n\n KeyError: 'chemises'\n
Nous allons r\u00e9soudre ce probl\u00e8me gr\u00e2ce \u00e0 :
"},{"location":"T2_Representation_des_donnees/2.3_Dictionnaires/cours/#27-test-dappartenance-a-un-dictionnaire","title":"2.7 Test d'appartenance \u00e0 un dictionnaire","text":"Exemple fondateur n\u00b07
Le mot in
permet de tester l'appartenance d'une cl\u00e9 \u00e0 un dictionnaire. Un bool\u00e9en est renvoy\u00e9.
>>> \"cravates\" in dressing\n False\n
"},{"location":"T2_Representation_des_donnees/2.3_Dictionnaires/cours/#3-exercices","title":"3. Exercices","text":"Exercice 2
\u00c9nonc\u00e9CorrectionAm\u00e9liorer la fonction achat(habit)
en y incluant un test pour prendre en compte les nouveaux habits.
def achat(habit):\n if habit in dressing:\n dressing[habit] += 1\n else:\n dressing[habit] = 1\n
Exercice 3
\u00c9nonc\u00e9CorrectionOn consid\u00e8re la liste suivante :
lst = ['Samuel', 'Pauline', 'Lina', 'Lina', 'Louis', 'Wa\u00ebll', 'Cl\u00e9ment', 'Khaled', 'Alexandre', 'Elie', 'Khaled', 'Khaled', 'Armand', 'Lina', 'Louis', 'Lina', 'Lina', 'Elie', 'Jules', 'Louis', 'Cl\u00e9ment', 'Khaled', 'Jules-Evan', 'Lina', 'Jules', 'Hadzo', 'Zoran', 'Cl\u00e9ment', 'Armand', 'Louis', 'Elie', 'Lina', 'Alexandre', 'Khaled', 'Iris', 'Gianni', 'Gianni', 'Pauline', 'Gianni', 'Elie', 'Iris', 'Armand', 'Louis', 'Cl\u00e9ment', 'Pauline', 'Zoran', 'Khaled', 'Zoran', 'Elie', 'Wa\u00ebll', 'Pauline', 'Lina', 'Alexandre', 'Khaled', 'Mehmet', 'Khaled', 'Hadzo', 'Zoran', 'Gianni', 'Jules', 'Paul', 'Pauline', 'Cl\u00e9ment', 'Alexandre', 'Iris', 'Khaled', 'Gianni', 'Elie', 'Jules', 'Khaled', 'Louis', 'Jules-Evan', 'Jules-Evan', 'Louis', 'Gianni', 'Elie', 'Cl\u00e9ment', 'Khaled', 'Louis', 'Louis', 'Emrys', 'Jules', 'Pauline', 'Armand', 'Elie', 'Jules', 'Elie', 'Khaled', 'Cl\u00e9ment', 'Louis', 'Khaled', 'Emrys', 'Samuel', 'Hadzo', 'Elie', 'Cl\u00e9ment', 'Alexandre', 'Hadzo', 'Lina', 'Iris', 'Alexandre', 'Mehmet', 'Elie', 'Jules', 'Khaled', 'Pauline', 'Samuel', 'Armand', 'Mehmet', 'Cl\u00e9ment', 'Jules', 'Armand', 'Mehmet', 'Lina', 'Armand', 'Cl\u00e9ment', 'Hadzo', 'Cl\u00e9ment', 'Emrys', 'Samuel', 'Zoran', 'Zoran', 'Zoran', 'Mehmet', 'Jules', 'Khaled', 'Khaled', 'Elie', 'Armand', 'Jules', 'Alexandre', 'Alexandre', 'Louis', 'Armand', 'Zoran', 'Iris', 'Cl\u00e9ment', 'Mehmet', 'Armand', 'Armand', 'Khaled', 'Lina', 'Lina', 'Jules', 'Louis', 'Paul', 'Pauline', 'Pauline', 'Pauline', 'Khaled', 'Lina', 'Wa\u00ebll', 'Zoran', 'Hadzo', 'Emrys', 'Gianni', 'Jules', 'Samuel', 'Gianni', 'Pauline', 'Wa\u00ebll', 'Cl\u00e9ment', 'Khaled', 'Jules', 'Jules', 'Louis', 'Zoran', 'Alexandre', 'Iris', 'Paul', 'Emrys', 'Armand', 'Wa\u00ebll', 'Zoran', 'Jules', 'Lina', 'Elie', 'Paul', 'Elie', 'Armand', 'Jules-Evan', 'Zoran', 'Alexandre', 'Zoran', 'Elie', 'Elie', 'Elie', 'Lina', 'Armand', 'Louis', 'Zoran', 'Lina', 'Armand', 'Alexandre', 'Samuel', 'Iris', 'Zoran', 'Paul', 'Pauline', 'Jules', 'Armand', 'Jules', 'Iris', 'Iris', 'Jules', 'Alexandre', 'Jules-Evan', 'Jules', 'Iris', 'Iris', 'Armand', 'Lina', 'Pauline', 'Zoran', 'Zoran', 'Pauline', 'Mehmet']\n
Cr\u00e9er un dictionnaire qui associera \u00e0 chaque pr\u00e9nom son nombre d'occurrences dans la liste.
occurrence = {}\n\nfor prenom in lst:\n if prenom in occurrence:\n occurrence[prenom] += 1\n else:\n occurrence[prenom] = 1\n
Exercice 4
\u00c9nonc\u00e9CorrectionOn consid\u00e8re la liste suivante : lst = ['5717', '1133', '5545', '4031', '6398', '2734', '3070', '1346', '7849', '7288', '7587', '6217', '8240', '5733', '6466', '7972', '7341', '6616', '5061', '2441', '2571', '4496', '4831', '5395', '8584', '3033', '6266', '2452', '6909', '3021', '5404', '3799', '5053', '8096', '2488', '8519', '6896', '7300', '5914', '7464', '5068', '1386', '9898', '8313', '1072', '1441', '7333', '5691', '6987', '5255']
Quel est le chiffre qui revient le plus fr\u00e9quemment dans cette liste ?
lst = ['5717', '1133', '5545', '4031', '6398', '2734', '3070', '1346', '7849', '7288', '7587', '6217', '8240', '5733', '6466', '7972', '7341', '6616', '5061', '2441', '2571', '4496', '4831', '5395', '8584', '3033', '6266', '2452', '6909', '3021', '5404', '3799', '5053', '8096', '2488', '8519', '6896', '7300', '5914', '7464', '5068', '1386', '9898', '8313', '1072', '1441', '7333', '5691', '6987', '5255']\n\nocc = {}\n\nfor nombre in lst:\n for chiffre in nombre:\n if chiffre in occ:\n occ[chiffre] += 1\n else:\n occ[chiffre] = 1\n\n# d\u00e9termination du max:\nocc_max = 0\n\nfor chiffre in occ:\n if occ[chiffre] > occ_max:\n occ_max = occ[chiffre]\n chiffre_max = chiffre\n\nprint(chiffre_max, 'est le chiffre le plus fr\u00e9quent')\nprint('il apparait', occ_max, 'fois')\n
Exercice 5
Exercice de bac
"},{"location":"T2_Representation_des_donnees/2.4_Bases/cours/","title":"2.4 Repr\u00e9sentation d'un entier positif dans diff\u00e9rentes bases","text":"Hormis la base 10, deux bases sont utilis\u00e9es en informatique :
Dans toute la suite, la base dans laquelle le nombre est \u00e9crit sera pr\u00e9cis\u00e9e en indice. Exemple : \\(13_{10}=1101_2=\\rm{D}_{16}\\)
"},{"location":"T2_Representation_des_donnees/2.4_Bases/cours/#1-le-systeme-binaire","title":"1. Le syst\u00e8me binaire","text":"En base 2, on ne dispose que des chiffres 0
et 1
. Le syst\u00e8me binaire est un syst\u00e8me de num\u00e9ration de position (comme le syst\u00e8me d\u00e9cimal, hexad\u00e9cimal... mais pas comme le syst\u00e8me romain). \u00c0 chaque rang correspond une puissance de 2.
\\(11010010_2=1 \\times 2^7+ 1 \\times 2^6+0 \\times 2^5+1 \\times 2^4+0 \\times 2^3+0 \\times 2^2+1 \\times 2^1+0 \\times 2^0=128+64+32+2=210_{10}\\)
Le nombre binaire 11010010 correspond donc au nombre d\u00e9cimal 210.
Code Python
En Python, on peut utiliser la fonction int(\"nombre\", base)
.
>>> int(\"11010010\", 2)\n210\n
"},{"location":"T2_Representation_des_donnees/2.4_Bases/cours/#12-du-decimal-vers-le-binaire","title":"1.2 Du d\u00e9cimal vers le binaire :","text":"Principe : dans chaque nombre d\u00e9cimal, il existe une plus grande puissance de 2 qui est inf\u00e9rieure au nombre.
Par exemple, dans 243, il y a 128. Donc \\(243=128 + (115)\\) \\(243=128+64+(51)\\) \\(243=128+64+32+(19)\\) \\(243=128+64+32+16+(3)\\) \\(243=128+64+32+16+2+1\\) \\(243=1 \\times 2^7+ 1 \\times 2^6+1 \\times 2^5+1 \\times 2^4+0 \\times 2^3+0 \\times 2^2+1 \\times 2^1+1 \\times 2^0\\)
Donc \\(243_{10}=11110011_2\\)
M\u00e9thode des divisions successives
Code Python
En Python, on peut utiliser la fonction bin(nombre)
. Elle renvoie une cha\u00eene de caract\u00e8re o\u00f9 le nombre binaire est pr\u00e9c\u00e9d\u00e9 de '0b'
.
>>> bin(243)\n'0b11110011'\n
Exercice 1
\u00c9nonc\u00e9CorrectionQuelle est la valeur maximale d'un octet (un octet = 8 chiffres binaires) ?
\\(11111111_2=255\\). On retrouve ce nombre comme \u00e9tant la valeur maximale d'une composante de couleur dans le codage RGB, ce qui signifie que chaque composante est cod\u00e9e sur un octet.
Exercice 2
\u00c9nonc\u00e9CorrectionCr\u00e9er une fonction binaire(n)
qui renvoie l'\u00e9criture binaire de n
, en utilisant les divisions successives.
def restes_successifs(n):\n''' renvoie la liste des restes successifs lors des divisions de n par 2'''\n restes = []\n while n != 0 :\n restes.append(n % 2)\n n = n // 2\n return restes\n\ndef binaire(n) :\n''' recompose le mot binaire en mettant dans l'ordre les restes successifs'''\n liste = restes_successifs(n)\n liste.reverse() #permet d'inverser l'ordre des \u00e9l\u00e9ment d'une liste\n mot = \"\"\n for k in liste :\n mot += str(k)\n return mot\n
"},{"location":"T2_Representation_des_donnees/2.4_Bases/cours/#2-le-systeme-hexadecimal","title":"2. Le syst\u00e8me hexad\u00e9cimal","text":"L'inconv\u00e9nient essentiel du syst\u00e8me binaire est la longueur de l'\u00e9criture des nombres qu'il g\u00e9n\u00e8re. Pour cette raison, le syst\u00e8me hexad\u00e9cimal, ou syst\u00e8me de base 16 est tr\u00e8s souvent employ\u00e9.
Pour \u00e9crire en base 2, il faut 2 chiffres diff\u00e9rents : le 0 et le 1.
Pour \u00e9crire en base 10, il faut 10 chiffres diff\u00e9rents: 0,1,2,3,4,5,6,7,8,9.
Pour \u00e9crire en base 16, il faut donc 16 chiffres diff\u00e9rents : 0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F.
On a donc la correspondance :
\\(\\rm{1D2}_{16}=1 \\times 16^2+ 13 \\times 16^1+2 \\times 16^0=256+208+2=466_{10}\\)
Le nombre hexad\u00e9cimal 1D2
correspond donc au nombre d\u00e9cimal 466.
En pratique, l'hexad\u00e9cimal est surtout utilis\u00e9 pour sa capacit\u00e9 \u00e0 repr\u00e9senter la valeur de n'importe quel octet sur 2 chiffres (\"chiffres\" \u00e9tant \u00e0 prendre au sens large = chiffres ou lettres !).
Exercice 3
\u00c9nonc\u00e9CorrectionFF
, 3A
, B2
.#8AFF33
.html
du blanc ?On peut utiliser la fonction hex(nombre)
. Elle renvoie une cha\u00eene de caract\u00e8re o\u00f9 le nombre hexad\u00e9cimal est pr\u00e9c\u00e9d\u00e9 de '0x'
.
>>> hex(125)\n'0x7d'\n
"},{"location":"T2_Representation_des_donnees/2.4_Bases/cours/#222-pour-passer-de-lhexadecimal-au-decimal","title":"2.2.2 Pour passer de l'hexad\u00e9cimal au d\u00e9cimal :","text":"On peut utiliser la fonction int(\"nombre\",base)
.
>>> int(\"FF\", 16)\n 255\n
"},{"location":"T2_Representation_des_donnees/2.4_Bases/cours/#3-du-binaire-inattendu","title":"3. Du binaire inattendu","text":"Le message secret de Perseverance
"},{"location":"T2_Representation_des_donnees/2.5_Booleens/05_Operateurs_booleens/","title":"Les op\u00e9rateurs bool\u00e9ens","text":""},{"location":"T2_Representation_des_donnees/2.5_Booleens/05_Operateurs_booleens/#reperes-historiques","title":"Rep\u00e8res historiques","text":"En 1847, le britannique George BOOLE inventa un formalisme permettant d'\u00e9crire des raisonnements logiques : l'alg\u00e8bre de Boole. La notion m\u00eame d'informatique n'existait pas \u00e0 l'\u00e9poque, m\u00eame si les calculs \u00e9taient d\u00e9j\u00e0 automatis\u00e9s (penser \u00e0 la Pascaline de 1642).
Bien plus tard, en 1938, les travaux de l'am\u00e9ricain Claude SHANNON prouva que des circuits \u00e9lectriques peuvent r\u00e9soudre tous les probl\u00e8mes que l'alg\u00e8bre de Boole peut elle-m\u00eame r\u00e9soudre. Pendant la deuxi\u00e8me guerre mondiale, les travaux d'Alan TURING puis de John VON NEUMANN poseront d\u00e9finitivement les bases de l'informatique moderne.
"},{"location":"T2_Representation_des_donnees/2.5_Booleens/05_Operateurs_booleens/#algebre-de-boole","title":"Alg\u00e8bre de Boole","text":"L'alg\u00e8bre de Boole d\u00e9finit des op\u00e9rations dans un ensemble qui ne contient que deux \u00e9l\u00e9ments not\u00e9s 0 et 1, ou bien FAUX et VRAI ,ou encore False et True (en Python)
Les op\u00e9rations fondamentales sont : - la conjonction (\"ET\") - la disjonction (\"OU\") - la n\u00e9gation (\"NON\").
Dans toute la suite, x
et y
d\u00e9signeront des Bool\u00e9ens (\u00e9l\u00e9ments d'une alg\u00e8bre de Boole) quelconques, F
d\u00e9signera FAUX et V
d\u00e9signera VRAI.
and
.
C'est l'op\u00e9ration d\u00e9finie par:
x & F = F
x & V = x
Puisque l'alg\u00e8bre de Boole ne contient que deux \u00e9l\u00e9ments, on peut \u00e9tudier tous les cas possibles et les regrouper dans un tableau appel\u00e9 table de v\u00e9rit\u00e9:
x
y
x & y
F F F F V F V F F V V V On repr\u00e9sente souvent les op\u00e9rateurs bool\u00e9ens \u00e0 l'aide de portes logiques:
Notation usuelle en \u00e9lectronique : \\(Q=A \\wedge B\\)
"},{"location":"T2_Representation_des_donnees/2.5_Booleens/05_Operateurs_booleens/#exemples-en-python","title":"Exemples en Python","text":"n = 20\n
(n % 10 == 0) and (n % 7 == 0)\n
False\n
(n % 4 == 0) and (n % 5 == 0)\n
True\n
"},{"location":"T2_Representation_des_donnees/2.5_Booleens/05_Operateurs_booleens/#levaluation-paresseuse","title":"L'\u00e9valuation paresseuse","text":"Pouvez-vous pr\u00e9voir le r\u00e9sultat du code ci-dessous ?
(n % 4 == 0) and (n % 0 == 0)\n
---------------------------------------------------------------------------\n\nZeroDivisionError Traceback (most recent call last)\n\n<ipython-input-3-d8a98dcba9be> in <module>\n----> 1 (n % 4 == 0) and (n % 0 == 0)\n\n\nZeroDivisionError: integer division or modulo by zero\n
\u00c9videmment, la division par 0 provoque une erreur. Mais observez maintenant ce code :
(n % 7 == 0) and (n % 0 == 0)\n
False\n
On appelle \u00e9valuation paresseuse le fait que l'interpr\u00e9teur Python s'arr\u00eate d\u00e8s que sa d\u00e9cision est prise : comme le premier bool\u00e9en vaut False et que la conjonction and
est appel\u00e9e, il n'est pas n\u00e9cessaire d'\u00e9valuer le deuxi\u00e8me bool\u00e9en.
or
C'est l'op\u00e9ration d\u00e9finie par:
C'est l'op\u00e9ration d\u00e9finie par:
x | V = V
x | F = x
On en d\u00e9duit la table suivante:
x
y
x or y
F F F F V V V F V V V V Notation usuelle en \u00e9lectronique : \\(Q=A \\vee B\\)
"},{"location":"T2_Representation_des_donnees/2.5_Booleens/05_Operateurs_booleens/#exemples-en-python_1","title":"Exemples en Python","text":"n = 20\n
(n % 10 == 0) or (n % 7 == 0)\n
True\n
(n % 4 == 0) or (n % 5 == 0)\n
True\n
(n % 7 == 0) or (n % 3 == 0)\n
False\n
"},{"location":"T2_Representation_des_donnees/2.5_Booleens/05_Operateurs_booleens/#levaluation-paresseuse-retour","title":"L'\u00e9valuation paresseuse (retour)","text":"Pouvez-vous pr\u00e9voir le r\u00e9sultat du code ci-dessous ?
(n % 5 == 0) or (n % 0 == 0)\n
"},{"location":"T2_Representation_des_donnees/2.5_Booleens/05_Operateurs_booleens/#negation-not","title":"N\u00e9gation (NOT)","text":"not
C'est l'op\u00e9ration d\u00e9finie par:
~V = F
~F = V
On en d\u00e9duit la table suivante:
x
~x
F V V F Notation usuelle en \u00e9lectronique : \\(Q=\\neg A\\)
"},{"location":"T2_Representation_des_donnees/2.5_Booleens/05_Operateurs_booleens/#exemples-en-python_2","title":"Exemples en Python","text":"n = 20\n
not(n % 10 == 0)\n
False\n
"},{"location":"T2_Representation_des_donnees/2.5_Booleens/05_Operateurs_booleens/#exercice-1","title":"Exercice 1","text":"Comprendre ce m\u00e8me.
"},{"location":"T2_Representation_des_donnees/2.5_Booleens/05_Operateurs_booleens/#exercice-2","title":"Exercice 2","text":"Exemple (inint\u00e9ressant) de circuit :
(en fran\u00e7ais OU EXCLUSIF)
x ^ y = (x & ~y) | (~x & y)
x
y
x ^ y
F F F F V V V F V V V F Le XOR joue un r\u00f4le fondamental en cryptographie car il poss\u00e8de une propri\u00e9t\u00e9 tr\u00e8s int\u00e9ressante : \\((x\\wedge y)\\wedge y=x\\)
Si \\(x\\) est un message et \\(y\\) une cl\u00e9 de chiffrage, alors \\(x\\wedge y\\) est le message chiffr\u00e9. Mais en refaisant un XOR du message chiffr\u00e9 avec la cl\u00e9 \\(y\\), on retrouve donc le message \\(x\\) initial.
"},{"location":"T2_Representation_des_donnees/2.5_Booleens/05_Operateurs_booleens/#fonction-non-et-nand","title":"Fonction Non Et (NAND)","text":"x \u2191 y = ~(x & y)
x
y
x \u2191 y
F F V F V V V F V V V F "},{"location":"T2_Representation_des_donnees/2.5_Booleens/05_Operateurs_booleens/#non-ou-nor","title":"Non Ou (NOR)","text":"x \u2193 y = ~(x & y)
x
y
x \u2193 y
F F V F V F V F F V V F Il est temps de se reposer un peu et d'admirer cette vid\u00e9o :
"},{"location":"T2_Representation_des_donnees/2.5_Booleens/05_Operateurs_booleens/#remarque","title":"Remarque :","text":"Les fonctions NAND ET NOR sont dites universelles : chacune d'entre elles peut g\u00e9n\u00e9rer l'int\u00e9gralit\u00e9 des autres portes logiques. Il est donc possible de coder toutes les op\u00e9rations uniquement avec des NAND (ou uniquement avec des NOR). Voir Wikipedia
"},{"location":"T2_Representation_des_donnees/2.5_Booleens/05_Operateurs_booleens/#exercice-4","title":"Exercice 4","text":"Calculer les op\u00e9rations suivantes.
1011011\n& 1010101\n----------\n\n\n 1011011\n| 1010101\n----------\n\n\n 1011011\n^ 1010101\n----------\n
solution
1011011\n& 1010101\n----------\n 1010001\n\n 1011011\n| 1010101\n----------\n 1011111\n\n 1011011\n^ 1010101\n----------\n 0001110\n
"},{"location":"T2_Representation_des_donnees/2.5_Booleens/05_Operateurs_booleens/#calculs-en-python","title":"Calculs en Python","text":"les op\u00e9rateurs &
, |
et ^
sont utilisables directement en Python
# calcul A\n12 & 7\n
4\n
# calcul B\n12 | 7\n
15\n
# calcul C\n12 ^ 5\n
9\n
Pour comprendre ces r\u00e9sultats, il faut travailler en binaire. Voici les m\u00eames calculs :
# calcul A\nbin(0b1100 & 0b111)\n
'0b100'\n
# calcul B\nbin(0b1100 | 0b111)\n
'0b1111'\n
# calcul C\nbin(0b1100 ^ 0b111)\n
'0b1011'\n
"},{"location":"T2_Representation_des_donnees/2.5_Booleens/05_Operateurs_booleens/#exercice-5-preparation-du-pydefi","title":"Exercice 5 : pr\u00e9paration du pyd\u00e9fi","text":"Objectif : chiffrer (= crypter) le mot \"BONJOUR\" avec la cl\u00e9 (de m\u00eame taille) \"MAURIAC\".
Protocole de chiffrage : XOR entre le code ASCII des lettres de m\u00eame position.
msg = \"BONJOUR\"\ncle = \"MAURIAC\"\n\ndef crypte_lettre(lm, lc):\n a = ord(lm)\n b = ord(lc)\n c = a^b\n lettre = chr(c)\n\n return lettre\n\ndef crypte_mot(mot1, mot2):\n mot3 = \"\"\n for i in range(len(mot1)):\n car = crypte_lettre(mot1[i],mot2[i])\n mot3 = mot3 + car\n return mot3\n\ncrypte_mot(msg, cle)\n
'\\x0f\\x0e\\x1b\\x18\\x06\\x14\\x11'\n
"},{"location":"T2_Representation_des_donnees/2.5_Booleens/05_Operateurs_booleens/#exercice-6","title":"Exercice 6 :","text":"R\u00e9solvez le pyd\u00e9fi la cl\u00e9 endommag\u00e9e
solution :
lien
"},{"location":"T2_Representation_des_donnees/2.5_Booleens/05_Operateurs_booleens/#complement-proprietes-des-operateurs-logiques","title":"Compl\u00e9ment : propri\u00e9t\u00e9s des op\u00e9rateurs logiques","text":"Les propri\u00e9t\u00e9s suivantes sont facilement d\u00e9montrables \u00e0 l'aide de tables de v\u00e9rit\u00e9s: (source : G.Connan)
Toutes ces lois sont ais\u00e9ment compr\u00e9hensibles si on les transpose en math\u00e9matiques : - & \u00e9quivaut \u00e0 \\(\\times\\) - \\(|\\) \u00e9quivaut \u00e0 \\(+\\) - \\(\\neg\\) \u00e9quivaut \u00e0 \\(-\\)
"},{"location":"T2_Representation_des_donnees/2.5_Booleens/cours/","title":"Les op\u00e9rateurs bool\u00e9ens","text":""},{"location":"T2_Representation_des_donnees/2.5_Booleens/cours/#1-reperes-historiques","title":"1. Rep\u00e8res historiques","text":"En 1847, le britannique George BOOLE inventa un formalisme permettant d'\u00e9crire des raisonnements logiques : l'alg\u00e8bre de Boole. La notion m\u00eame d'informatique n'existait pas \u00e0 l'\u00e9poque, m\u00eame si les calculs \u00e9taient d\u00e9j\u00e0 automatis\u00e9s (penser \u00e0 la Pascaline de 1642).
Bien plus tard, en 1938, les travaux de l'am\u00e9ricain Claude SHANNON prouva que des circuits \u00e9lectriques peuvent r\u00e9soudre tous les probl\u00e8mes que l'alg\u00e8bre de Boole peut elle-m\u00eame r\u00e9soudre. Pendant la deuxi\u00e8me guerre mondiale, les travaux d'Alan TURING puis de John VON NEUMANN poseront d\u00e9finitivement les bases de l'informatique moderne.
"},{"location":"T2_Representation_des_donnees/2.5_Booleens/cours/#2-algebre-de-boole","title":"2. Alg\u00e8bre de Boole","text":"L'alg\u00e8bre de Boole d\u00e9finit des op\u00e9rations dans un ensemble qui ne contient que deux \u00e9l\u00e9ments not\u00e9s 0 et 1, ou bien FAUX et VRAI ,ou encore False et True (en Python)
Les op\u00e9rations fondamentales sont :
Dans toute la suite, x
et y
d\u00e9signeront des Bool\u00e9ens (\u00e9l\u00e9ments d'une alg\u00e8bre de Boole) quelconques, F
d\u00e9signera FAUX et V
d\u00e9signera VRAI.
and
.
C'est l'op\u00e9ration d\u00e9finie par:
x & F = F
x & V = x
Puisque l'alg\u00e8bre de Boole ne contient que deux \u00e9l\u00e9ments, on peut \u00e9tudier tous les cas possibles et les regrouper dans un tableau appel\u00e9 table de v\u00e9rit\u00e9:
Table de v\u00e9rit\u00e9 de AND
x
y
x & y
F F F F V F V F F V V V On repr\u00e9sente souvent les op\u00e9rateurs bool\u00e9ens \u00e0 l'aide de portes logiques:
Notation usuelle en \u00e9lectronique : \\(Q=A \\wedge B\\)
"},{"location":"T2_Representation_des_donnees/2.5_Booleens/cours/#exemples-en-python","title":"Exemples en Python","text":">>> n = 20\n>>> (n % 10 == 0) and (n % 7 == 0)\nFalse\n>>> (n % 4 == 0) and (n % 5 == 0)\nTrue\n
"},{"location":"T2_Representation_des_donnees/2.5_Booleens/cours/#levaluation-paresseuse","title":"L'\u00e9valuation paresseuse","text":"Pouvez-vous pr\u00e9voir le r\u00e9sultat du code ci-dessous ?
>>> (n % 4 == 0) and (n % 0 == 0)\n ---------------------------------------------------------------------------\n\n ZeroDivisionError Traceback (most recent call last)\n\n <ipython-input-3-d8a98dcba9be> in <module>\n ----> 1 (n % 4 == 0) and (n % 0 == 0)\n\n\n ZeroDivisionError: integer division or modulo by zero\n
\u00c9videmment, la division par 0 provoque une erreur. Mais observez maintenant ce code :
>>> (n % 7 == 0) and (n % 0 == 0)\nFalse\n
On appelle \u00e9valuation paresseuse le fait que l'interpr\u00e9teur Python s'arr\u00eate d\u00e8s que sa d\u00e9cision est prise : comme le premier bool\u00e9en vaut False et que la conjonction and
est appel\u00e9e, il n'est pas n\u00e9cessaire d'\u00e9valuer le deuxi\u00e8me bool\u00e9en.
or
C'est l'op\u00e9ration d\u00e9finie par:
C'est l'op\u00e9ration d\u00e9finie par:
x | V = V
x | F = x
On en d\u00e9duit la table suivante:
Table de v\u00e9rit\u00e9 de OR
x
y
x or y
F F F F V V V F V V V V Notation usuelle en \u00e9lectronique : \\(Q=A \\vee B\\)
"},{"location":"T2_Representation_des_donnees/2.5_Booleens/cours/#exemples-en-python_1","title":"Exemples en Python","text":">>> n = 20\n>>> (n % 10 == 0) or (n % 7 == 0)\nTrue\n>>> (n % 4 == 0) or (n % 5 == 0)\nTrue\n>>> (n % 7 == 0) or (n % 3 == 0)\nFalse\n
"},{"location":"T2_Representation_des_donnees/2.5_Booleens/cours/#levaluation-paresseuse-retour","title":"L'\u00e9valuation paresseuse (retour)","text":"Pouvez-vous pr\u00e9voir le r\u00e9sultat du code ci-dessous ?
>>> (n % 5 == 0) or (n % 0 == 0)\n
"},{"location":"T2_Representation_des_donnees/2.5_Booleens/cours/#23-negation-not","title":"2.3 N\u00e9gation (NOT)","text":"not
C'est l'op\u00e9ration d\u00e9finie par:
~V = F
~F = V
On en d\u00e9duit la table suivante:
Table de v\u00e9rit\u00e9 de NOT
x
~x
F V V F Notation usuelle en \u00e9lectronique : \\(Q=\\neg A\\)
"},{"location":"T2_Representation_des_donnees/2.5_Booleens/cours/#exemples-en-python_2","title":"Exemples en Python","text":">>> n = 20\n>>> not(n % 10 == 0)\nFalse\n
"},{"location":"T2_Representation_des_donnees/2.5_Booleens/cours/#24-exercice-1","title":"2.4 Exercice 1","text":"Comprendre ce m\u00e8me :
"},{"location":"T2_Representation_des_donnees/2.5_Booleens/cours/#25-exercice-2","title":"2.5 Exercice 2","text":"Exercice 2
Ouvrir le simulateur de circuits et cr\u00e9er pour chaque op\u00e9ration AND, OR, NOT un circuit \u00e9lectrique illustrant ses propri\u00e9t\u00e9s.
Exemple (inint\u00e9ressant) de circuit :
"},{"location":"T2_Representation_des_donnees/2.5_Booleens/cours/#3-fonctions-composees","title":"3. Fonctions compos\u00e9es","text":""},{"location":"T2_Representation_des_donnees/2.5_Booleens/cours/#31-disjonction-exclusive-xor","title":"3.1 Disjonction exclusive XOR","text":"(en fran\u00e7ais OU EXCLUSIF)
x ^ y = (x & ~y) | (~x & y)
Table de v\u00e9rit\u00e9 de XOR
x
y
x ^ y
F F F F V V V F V V V F Le XOR joue un r\u00f4le fondamental en cryptographie car il poss\u00e8de une propri\u00e9t\u00e9 tr\u00e8s int\u00e9ressante : \\((x\\wedge y)\\wedge y=x\\)
Si \\(x\\) est un message et \\(y\\) une cl\u00e9 de chiffrage, alors \\(x\\wedge y\\) est le message chiffr\u00e9. Mais en refaisant un XOR du message chiffr\u00e9 avec la cl\u00e9 \\(y\\), on retrouve donc le message \\(x\\) initial.
"},{"location":"T2_Representation_des_donnees/2.5_Booleens/cours/#32-fonction-non-et-nand","title":"3.2 Fonction Non Et (NAND)","text":"x \u2191 y = ~(x & y)
Table de v\u00e9rit\u00e9 de NAND
x
y
x \u2191 y
F F V F V V V F V V V F "},{"location":"T2_Representation_des_donnees/2.5_Booleens/cours/#33-fonction-non-ou-nor","title":"3.3 Fonction Non Ou (NOR)","text":"x \u2193 y = ~(x & y)
Table de v\u00e9rit\u00e9 de NOR
x
y
x \u2193 y
F F V F V F V F F V V F Il est temps de se reposer un peu et d'admirer cette vid\u00e9o :
"},{"location":"T2_Representation_des_donnees/2.5_Booleens/cours/#remarque","title":"Remarque :","text":"
Les fonctions NAND ET NOR sont dites universelles : chacune d'entre elles peut g\u00e9n\u00e9rer l'int\u00e9gralit\u00e9 des autres portes logiques. Il est donc possible de coder toutes les op\u00e9rations uniquement avec des NAND (ou uniquement avec des NOR). Voir Wikipedia
"},{"location":"T2_Representation_des_donnees/2.5_Booleens/cours/#34-exercice-4","title":"3.4 Exercice 4","text":"Exercice 4
\u00c9nonc\u00e9CorrectionEffectuer les op\u00e9rations suivantes.
1011011\n& 1010101\n----------\n\n\n 1011011\n| 1010101\n----------\n\n\n 1011011\n^ 1010101\n----------\n
1011011\n&1010101\n----------\n 1010001\n\n 1011011\n|1010101\n----------\n 1011111\n\n 1011011\n^1010101\n----------\n 0001110\n
"},{"location":"T2_Representation_des_donnees/2.5_Booleens/cours/#35-calculs-en-python","title":"3.5 Calculs en Python","text":"les op\u00e9rateurs &
, |
et ^
sont utilisables directement en Python
# calcul A\n>>> 12 & 7\n4\n
# calcul B\n>>> 12 | 7\n15\n
# calcul C\n>>> 12 ^ 5\n9\n
Pour comprendre ces r\u00e9sultats, il faut travailler en binaire. Voici les m\u00eames calculs :
# calcul A\n>>> bin(0b1100 & 0b111)\n '0b100'\n
# calcul B\n>>> bin(0b1100 | 0b111)\n '0b1111'\n
# calcul C\n>>> bin(0b1100 ^ 0b111)\n '0b1011'\n
"},{"location":"T2_Representation_des_donnees/2.5_Booleens/cours/#exercice-5-cryptographie","title":"Exercice 5 : Cryptographie","text":"Exercice 5
On souhaite chiffrer (chiffrer est le mot utilis\u00e9 en cryptographie pour crypter) le mot \"BONJOUR\"
avec la cl\u00e9 \"MAURIAC\"
. Le chiffrement retenu est un chiffrement par XOR, ce qui signifie qu'on va effectuer un XOR entre les deux nombres associ\u00e9s aux lettres.
Exemple :
'B'
va \u00eatre chiffr\u00e9e gr\u00e2ce au 'M'
.'B'
est 66. (on le sait car ord('B')
renvoie 66 )'M'
est 77. (on le sait car ord('M')
renvoie 77 )'\\x0f'
(on le sait car chr(15)
renvoie '\\x0f'
)Le premier caract\u00e8re du mot chiffr\u00e9 sera donc '\\x0f'
Q1. \u00c9crire une fonction chiffre
qui prendra en param\u00e8tre un mot mot_clair
et un mot de passe cle
de m\u00eame taille que mot_clair
et qui renvoie la cha\u00eene de caract\u00e8res obtenue en XORant mot_clair
avec cle
.
Q2. Chiffrer le mot \"BONJOUR\"
avec la cl\u00e9 \"MAURIAC\"
.
Q3. Reprendre la cha\u00eene de caract\u00e8res pr\u00e9c\u00e9demment obtenue et la rechiffrer \u00e0 nouveau avec la cl\u00e9 \"MAURIAC\"
. Que constate-t-on ? Etait-ce pr\u00e9visible ?
Q4. R\u00e9soudre le Pyd\u00e9fi La cl\u00e9 endommag\u00e9e
"},{"location":"T2_Representation_des_donnees/2.5_Booleens/cours/#complement-mathematique-proprietes-des-operateurs-logiques","title":"Compl\u00e9ment math\u00e9matique: propri\u00e9t\u00e9s des op\u00e9rateurs logiques","text":"Les propri\u00e9t\u00e9s suivantes sont facilement d\u00e9montrables \u00e0 l'aide de tables de v\u00e9rit\u00e9s: (source : G.Connan)
Toutes ces lois sont ais\u00e9ment compr\u00e9hensibles si on les transpose en math\u00e9matiques :
Vous pouvez faire cette \u00e9nigme sur Capytale https://capytale2.ac-paris.fr/web/c/5912-1397991
"},{"location":"T2_Representation_des_donnees/2.5_Booleens/enonce/#1-a-la-recherche-du-personnage-mystere","title":"1. \u00c0 la recherche du personnage myst\u00e8re","text":"Vous avez trouv\u00e9 une image bien \u00e9trange :
Un visage semble se deviner derri\u00e8re un champ de fleurs... mais quel est ce visage ?
L'image du champ de fleurs ne vous est pas inconnue, d'ailleurs en cherchant bien vous l'avez retrouv\u00e9e dans vos dossiers :
On dirait que le personnage-myst\u00e8re a voulu se fondre dans le champ de fleurs...
XORez-vous d\u00e9couvrir qui est ce personnage-myst\u00e8re ?
"},{"location":"T2_Representation_des_donnees/2.5_Booleens/enonce/#2-aide-pour-la-manipulation-dimages-et-lextraction-de-pixels","title":"2. Aide pour la manipulation d'images et l'extraction de pixels","text":""},{"location":"T2_Representation_des_donnees/2.5_Booleens/enonce/#21-code-de-demarrage","title":"2.1 Code de d\u00e9marrage","text":"from PIL import Image\n\nimg_myst = Image.open(\"mystere.bmp\")\nimg_mask = Image.open(\"mask.jpg\")\n\nlargeur = img_myst.width\nhauteur = img_myst.height\n\nimg_new = Image.new('RGB', img_myst.size)\n
"},{"location":"T2_Representation_des_donnees/2.5_Booleens/enonce/#22-manipulation-de-pixels","title":"2.2 Manipulation de pixels","text":"Les expressions ci-dessous sont \u00e0 tester pour en comprendre le fonctionnement.
"},{"location":"T2_Representation_des_donnees/2.5_Booleens/enonce/#221-recuperer-le-code-rgb-un-pixel","title":"2.2.1 R\u00e9cup\u00e9rer le codeRGB
un pixel","text":">>> img_myst.getpixel((125, 80))\n(54, 217, 174)\n
Le pixel de coordonn\u00e9es (125, 80) a pour composantes RGB (54, 217, 174)."},{"location":"T2_Representation_des_donnees/2.5_Booleens/enonce/#222-modifier-la-couleur-dun-pixel","title":"2.2.2 Modifier la couleur d'un pixel","text":">>> img_new.putpixel((30,70), (255,0,0))\n>>> \n
Le pixel de coordonn\u00e9es (30, 70) est maintenant un pixel rouge."},{"location":"T2_Representation_des_donnees/2.5_Booleens/enonce/#223-afficher-une-image","title":"2.2.3 Afficher une image","text":">>> img_mask.show()\n
"},{"location":"T2_Representation_des_donnees/2.5_Booleens/enonce/#224-sauvegarder-une-image","title":"2.2.4 Sauvegarder une image","text":">>> img_new.save(\"solution.png\")\n
"},{"location":"T2_Representation_des_donnees/2.6_Codage_caracteres/cours/","title":"2.6 Codage des caract\u00e8res","text":"Tout pour comprendre et \u00c3\u00a9viter les erreurs d'encodage
"},{"location":"T2_Representation_des_donnees/2.6_Codage_caracteres/cours/#1-au-commencement-etait-lascii","title":"1. Au commencement \u00e9tait l'ASCII","text":"pour American Standard Code for Information Interchange, cr\u00e9\u00e9 en 1960 aux \u00c9tats-Unis.
En ASCII, 127 \u00abpoints de code\u00bb (nombres associ\u00e9s aux caract\u00e8res) sont disponibles. Les caract\u00e8res sont donc cod\u00e9s sur 7 bits.
Exercice
\u00c9nonc\u00e9AideCorrectionD\u00e9coder l'expression suivante, \u00e9crite en ASCII :
1101100 1100101 1110011 100000 1001110 1010011 1001001 100000 1100011 100111 1100101 1110011 1110100 100000 1101100 1100101 1110011 100000 1101101 1100101 1101001 1101100 1101100 1100101 1110101 1110010 1110011
split(\" \")
permet de d\u00e9composer une chaine de caract\u00e8res en une liste, en se servant de l'espace \" \"
comme caract\u00e8re s\u00e9parateur.int(\"1101100\",2)
permet de r\u00e9cup\u00e9rer facilement la valeur en base 10 du nombre binaire 1101100
.msg = \"1101100 1100101 1110011 100000 1001110 1010011 1001001 100000 1100011 100111 1100101 1110011 1110100 100000 1101100 1100101 1110011 100000 1101101 1100101 1101001 1101100 1101100 1100101 1110101 1110010 1110011\"\nmsg = msg.split(' ')\ns = \"\"\nfor k in msg :\n s += chr(int(k,2))\nprint(s)\n
"},{"location":"T2_Representation_des_donnees/2.6_Codage_caracteres/cours/#2-et-le-reste-du-monde","title":"2. Et le reste du monde ?","text":"Lorsque d'autres personnes que des americains ou des anglais ont voulu s'\u00e9changer des donn\u00e9es faisant intervenir du texte, certains caract\u00e8res (\u00e9, \u00e8, \u00e0, \u00f1, \u00d8, \u00d6, \u03b2, \u6f22...) \u00e9taient manquants. Les 127 caract\u00e8res de l'ASCII \u00e9taient largement insuffisants. Il a donc \u00e9t\u00e9 d\u00e9cid\u00e9 de passer \u00e0... 256 caract\u00e8res ! Il suffisait pour cela de coder les caract\u00e8res non plus sur 7 bits mais sur 8 bits.
Ainsi naqu\u00eet, apr\u00e8s de nombreuses modifications successives (la derni\u00e8re en date rajoutant par exemple le symbole \u20ac), la c\u00e9l\u00e8bre table ISO 8859-15, dite aussi Latin-9 :
"},{"location":"T2_Representation_des_donnees/2.6_Codage_caracteres/cours/#utilisation","title":"Utilisation :","text":"Les codes sont donn\u00e9s en hexad\u00e9cimal :
65... comme en ASCII ! Oui, la (seule) bonne id\u00e9e aura \u00e9t\u00e9 d'inclure les caract\u00e8res ASCII avec leur m\u00eame code, ce qui rendait cette nouvelle norme r\u00e9tro-compatible.
Exemple :
Le fichier test.txt
contient un texte enregistr\u00e9 avec l'encodage Latin-9. Ce fichier est ensuite ouvert avec un \u00e9diteur hexad\u00e9cimal, qui permet d'observer la valeur des octets qui composent le fichier. (Comme le fichier est un .txt, le fichier ne contient que les donn\u00e9es et rien d'autre.)
Parfait, mais comment font les Grecs pour \u00e9crire leur alphabet ? Pas de probl\u00e8me, il leur suffit d'utiliser... une autre table, appel\u00e9e ISO-8859-7 :
On retrouve les caract\u00e8res universels h\u00e9rit\u00e9s de l'ASCII, puis des caract\u00e8res sp\u00e9cifiques \u00e0 la langue grecque... oui mais les Tha\u00eflandais alors ?
Pas de probl\u00e8me, ils ont la ISO-8859-11 :
\u00c9videmment, quand tous ces gens veulent discuter entre eux, les probl\u00e8mes d'encodage surviennent imm\u00e9diatement : certains caract\u00e8res sont remplac\u00e9s par d'autres.
"},{"location":"T2_Representation_des_donnees/2.6_Codage_caracteres/cours/#3-que-fait-un-logiciel-a-louverture-dun-fichier-texte","title":"3. Que fait un logiciel \u00e0 l'ouverture d'un fichier texte ?","text":"Il essaie de deviner l'encodage utilis\u00e9... Parfois cela marche, parfois non.
Normalement, pour un navigateur, une page web correctement cod\u00e9e doit contenir dans une balise meta
le charset
utilis\u00e9.
Mais parfois, il n'y a pas d'autre choix pour le logiciel d'essayer de deviner l'encodage qui semble \u00eatre utilis\u00e9.
Exercice
\u00c9nonc\u00e9CorrectionLe mot repr\u00e9sent\u00e9 par les octets ci-dessous est-il encod\u00e9 en ASCII ou en Latin-9 ?
C'est du Latin-9, et c'est le mot \"v\u00e9lo\"
"},{"location":"T2_Representation_des_donnees/2.6_Codage_caracteres/cours/#4-enfin-une-normalisation-larrivee-de-lutf","title":"4. Enfin une normalisation : l'arriv\u00e9e de l'UTF","text":"En 1996, le Consortium Unicode d\u00e9cide de normaliser tout cela et de cr\u00e9er un syst\u00e8me unique qui contiendra l'int\u00e9gralit\u00e9 des caract\u00e8res dont les \u00eatres humains ont besoin pour communiquer entre eux.
Ils cr\u00e9ent l'Universal character set Transformation Format : l'UTF. Ou plut\u00f4t ils en cr\u00e9ent... plusieurs :
Pourquoi est-ce encore si compliqu\u00e9 ? En UTF-32, 32 bits sont disponibles, soit \\(2^{32}=4294967296\\) caract\u00e8res diff\u00e9rents encodables.
C'est largement suffisant, mais c'est surtout tr\u00e8s tr\u00e8s lourd ! D'autres encodages plus l\u00e9gers, mais plus complexes, sont donc propos\u00e9s :
Arr\u00eatons-nous sur l'UTF-8 :
Le principe fondateur de l'UTF-8 est qu'il est adaptatif : les carac\u00e8res les plus fr\u00e9quents sont cod\u00e9s sur un octet, qui est la taille minimale (et qui donne le 8 de \"UTF-8\"). Les autres caract\u00e8res peuvent \u00eatre cod\u00e9s sur 2, 3 ou 4 octets au maximum.
"},{"location":"T2_Representation_des_donnees/2.6_Codage_caracteres/cours/#5-la-reponse-a-une-question-existentielle","title":"5. La r\u00e9ponse \u00e0 une question existentielle","text":"Pourquoi le caract\u00e8re \u00e9
en UTF-8 devient-il \u00c3\u00a9
en ISO 8859-15 ?
Q1. Gr\u00e2ce \u00e0 la fonction ord
puis \u00e0 la fonction bin
, \u00e9crire en binaire le nombre associ\u00e9 au caract\u00e8re \u00e9
en UTF-8.
>>> ord('\u00e9')\n233\n>>> bin(233)\n'0b11101001'\n
Donc en UTF-8, \u00e9
est associ\u00e9 au nombre 11101001
. Q2. D'apr\u00e8s l'explication de fonctionnement de l'encodage adaptatif de l'UTF-8 (voir ci-dessus), les 8 bits n\u00e9cessaires \u00e0 l'encodage de \u00e9
en UTF-8 vont \u00eatre \u00abencapsul\u00e9s\u00bb dans 2 octets de la forme 110XXXXX 10XXXXXX
, o\u00f9 les 11 X
repr\u00e9sentent les 11 bits d'information disponibles. \u00c9crire ces 2 octets en compl\u00e9tant si n\u00e9cessaire avec des 0
\u00e0 gauche.
Sur 11 bits, le nombre 11101001
va s'\u00e9crire 00011101001
. En s\u00e9parant ces 11 bits en deux groupes de 5 bits et 6 bits (00011
et 101001
), et en les encapsulant, on obtient les deux octets 11000011 10101001
.
Q3. Convertir les deux octets obtenus en notation d\u00e9cimale (gr\u00e2ce \u00e0 int
) puis en hexad\u00e9cimal (gr\u00e2ce \u00e0 hex
).
>>> int('11000011', 2)\n195\n>>> hex(195)\n'0xc3'\n>>> int('10101001', 2)\n169\n>>> hex(169)\n'0xa9'\n
Q4. Si un logiciel consid\u00e8re \u00e0 tort que les deux octets servant \u00e0 encoder le \u00e9
en UTF-8 servent \u00e0 encoder deux caract\u00e8res en ISO 8859-15, quels seront ces deux caract\u00e8res ?
Le premier octet, c3
en hexad\u00e9cimal, sera per\u00e7u en ISO 8859-15 comme le caract\u00e8re \u00c3
. Le deuxi\u00e8me octet, a9
en hexad\u00e9cimal, sera per\u00e7u en ISO 8859-15 comme la lettre \u00a9
.
Finalement, ce qui aurait d\u00fb \u00eatre un \u00e9
en UTF-8 se retrouvera \u00eatre un \u00c3\u00a9
en ISO 8859-15.
La majorit\u00e9 des sites internet utilisent maintenant l'UTF-8, tout comme les syst\u00e8mes d'exploitation r\u00e9cents.
"},{"location":"T2_Representation_des_donnees/2.7_Codage_entiers/cours/","title":"2.7 Codage des entiers","text":"Attention
La mani\u00e8re dont les nombres (entiers, non-entiers, positifs, n\u00e9gatifs...) sont trait\u00e9s par un langage de programmation est sp\u00e9cifique \u00e0 ce langage.
Dans toute la suite de ce cours, pour simplifier, nous consid\u00e9rerons que les nombres sont cod\u00e9s sur 1 octet seulement. Ce qui ne correspond pas \u00e0 la r\u00e9alit\u00e9, mais permet de comprendre les notions essentielles.
"},{"location":"T2_Representation_des_donnees/2.7_Codage_entiers/cours/#1-les-nombres-entiers-en-binaire-non-signe","title":"1. Les nombres entiers en binaire non sign\u00e9","text":"L'expression \"non sign\u00e9\" signifie que la contrainte du signe n'existe pas : tous les nombres sont consid\u00e9r\u00e9s comme \u00e9tant positifs.
Nous avons d\u00e9j\u00e0 vu comment ces nombres se codaient en binaire.
Sur un octet, le nombre minimal qu'on puisse coder est 00000000
. C'est l'entier naturel 0. Le nombre maximal qu'on puisse coder est 11111111
. C'est l'entier naturel 255.
Exercice
\u00c9nonc\u00e9CorrectionPython et les entiers
Depuis la version 3 du langage Python, il n'y a plus de taille maximale pour les entiers en Python.
Ceci implique que la taille n\u00e9cessaire au codage de l'entier est allou\u00e9e dynamiquement par Python (avec pour seule limite celle de la m\u00e9moire disponible).
Exercice
\u00c9nonc\u00e9Correction00001101
et 00001011
.Comment diff\u00e9rencier les nombres positifs des nombres n\u00e9gatifs ? L'id\u00e9e naturelle est de r\u00e9server 1 bit pour le signe, et de coder le reste du nombre \u00abnaturellement\u00bb.
Par exemple, on peut d\u00e9cr\u00e9ter que le premier bit (appel\u00e9 bit de poids fort) sera le bit de signe :
Dans ce cas, 00000011
serait le nombre \\(+3\\) et 10000011
serait le nombre \\(-3\\).
Probl\u00e8mes :
00000000
et 10000000
, ce qui n'est pas tr\u00e8s \u00e9conome.Moralit\u00e9 :
Ce syst\u00e8me d'\u00e9criture ne marche pas bien.
"},{"location":"T2_Representation_des_donnees/2.7_Codage_entiers/cours/#22-a-la-recherche-de-loppose-dun-nombre","title":"2.2 \u00c0 la recherche de l'oppos\u00e9 d'un nombre","text":"Id\u00e9e :
Plut\u00f4t que de chercher \u00e0 \u00e9crire directement le nombre \\(-3\\), nous allons chercher \u00e0 d\u00e9terminer ce qu'il faut ajouter \u00e0 \\((+3)\\) pour obtenir 0.
Que faut-il ajouter au nombre \\((+3)\\) pour obtenir 0 ?
L'id\u00e9e naturelle est de commencer par la droite, en essayant de \u00abfabriquer du z\u00e9ro\u00bb en choisissant le bon bit \u00e0 ajouter :
On arrive bien \u00e0 fabriquer des 0 sur tout notre octet, mais que devient la retenue (en anglais carry) de 1 qui d\u00e9borde de notre octet ?
R\u00e9ponse : rien ! Elle sera perdue et c'est une tr\u00e8s bonne nouvelle. Ce nombre sera donc consid\u00e9r\u00e9 comme un 0 : nous avons trouv\u00e9 comment coder \\(-3\\).
Le nombre \\(-3\\) s'\u00e9crit donc 11111101
.
Comment, \u00e0 partir du nombre 00000011
, aurait-on pu le trouver directement (sans raisonner de proche en proche) ?
On peut remarquer qu'en inversant chaque bit du nombre de d\u00e9part 00000011
, on obtient 11111100
, qui appel\u00e9 le compl\u00e9ment \u00e0 2 du nombre 00000011
.
Il ne reste donc plus qu'\u00e0 ajouter 1
\u00e0 ce nombre 11111100
pour obtenir le nombre cherch\u00e9, 11111101
ce nombre 11111101
repr\u00e9sente 253 en codage non sign\u00e9. Il est donc n\u00e9cessaire, lorsqu'on repr\u00e9sente un nombre, de savoir si les nombres manipul\u00e9s seront des entiers naturels (non sign\u00e9s) ou bien relatifs (sign\u00e9s).
Consid\u00e9rons que ce nombre positif s'\u00e9crit sur 7 bits, donc qu'il est de la forme 0XXXXXXX
.
\u00c9criture de l'oppos\u00e9 d'un nombre positif
Exercice
\u00c9nonc\u00e9CorrectionDonner l'\u00e9criture binaire sur un octet du nombre \\(-13\\).
Commen\u00e7ons par \u00e9crire le nombre 13 en binaire. Il s'\u00e9crit \u00a000001101
.
11110010
.11110011
. Le nombre \\(-13\\) s'\u00e9crit donc 11110011
.
Remarque Les nombres n\u00e9gatifs commenceront donc toujours par le bit 1, et les nombres positifs par le bit 0. Cela revient \u00e0 suivre partiellement notre fausse bonne id\u00e9e du 2.1. Et cela donne surtout une m\u00e9thode tr\u00e8s pratique pour savoir qui est positif et qui est n\u00e9gatif !
"},{"location":"T2_Representation_des_donnees/2.7_Codage_entiers/cours/#3-travail-inverse-passage-du-binaire-signe-au-nombre-relatif","title":"3. Travail inverse : passage du binaire sign\u00e9 au nombre relatif","text":"Consid\u00e9rons le nombre 11101101
, cod\u00e9 en binaire sign\u00e9. \u00c0 quel nombre relatif correspond-il ?
11101100
.00010011
.Exercice
\u00c9nonc\u00e9Correction11110001
?11110001
- 1
= 11110000
. En prenant le compl\u00e9ment \u00e0 2, on trouve 00001111
, qui vaut 15. Le nombre 11110001
repr\u00e9sente donc \\(-15\\).01111111
, soit \\(+127\\).10000000
. 10000000
- 1
= 01111111
. Le compl\u00e9ment est 10000000
, qui est \u00e9gal \u00e0 128. Donc le nombre minimal est \\(-128\\).Le 04 juin 1996, le vol inaugural d'Ariane 5 a malheureusement fini dans une gerbe d'\u00e9tincelles.
En cause : un code pr\u00e9vu pour Ariane 4 avait \u00e9t\u00e9 gard\u00e9 pour le nouveau mod\u00e8le Ariane 5. Dans ce \u00abvieux\u00bb code, une donn\u00e9e issue d'un capteur (le capteur de vitesse horizontale) \u00e9tait cod\u00e9 sur 8 bits. La valeur maximale acceptable de cette donn\u00e9e \u00e9tait donc 255.
Or, Ariane 5 \u00e9tant beaucoup plus puissante, le capteur de vitesse horizontale a renvoy\u00e9, au bout de 30 secondes, la valeur 300 : cette valeur a provoqu\u00e9 un d\u00e9passement des 8 bits pr\u00e9vus et a donn\u00e9 un r\u00e9sultat absurde. L'ordinateur de bord a cru que la fus\u00e9e \u00e9tait en train de se coucher et a violemment orient\u00e9 les tuy\u00e8res de propulsion pour redresser Ariane 5, alors que celle-ci s'\u00e9levait pourtant bien verticalement... Ariane 5 a alors brusquement pivot\u00e9 avant d'exploser.
Cette catastrophe (150 millions d'euros et des ann\u00e9es de travail perdus) a fait prendre conscience \u00e0 la communaut\u00e9 scientifique de l'importance de faire des tests logiciels toujours plus pouss\u00e9s : ce n'est pas parce qu'un code marche dans un environnement donn\u00e9 qu'il marchera de la m\u00eame mani\u00e8re dans d'autres conditions...
"},{"location":"T2_Representation_des_donnees/2.7_Codage_entiers/cours/#42-le-bug-de-lannee-2038","title":"4.2 Le bug de l'ann\u00e9e 2038","text":"Expliquons ce (superbe) gif issu de la page Wikipedia Bug de l'an 2038.
Lorsqu'on demande \u00e0 Python l'heure qu'il est, par la fonction time()
du module time
, voici ce qu'il r\u00e9pond :
>>> import time\n>>> time.time()\n1653855138.398177\n
Il nous renvoie le nombre de secondes \u00e9coul\u00e9es depuis le 1er janvier 1970 \u00e0 00h00. On appelle cela l'heure POSIX ou l'heure UNIX l'heure UNIX. Au 29 mai 2022, il s'en donc \u00e9coul\u00e9 environ 1,6 milliards.
Dans beaucoup de syst\u00e8mes informatiques, ce nombre de secondes est cod\u00e9 par un entier sign\u00e9 sur 32 bits. Le nombre maximum de secondes qui peut \u00eatre repr\u00e9sent\u00e9 est donc 01111111 11111111 11111111 11111111
>>> int('01111111111111111111111111111111', 2)\n2147483647\n
Ce nombre repr\u00e9sente un peu plus de 2 milliards de secondes... En les comptant depuis le 01/01/1970 00h00m00s, on arrive au 19/01/2038 \u00e0 03h14m07s.
\u00c0 la seconde d'apr\u00e8s, la repres\u00e9ntation binaire du temps sera 10000000 00000000 00000000 00000000
, qui sera interpr\u00e9t\u00e9 comme le nombre n\u00e9gatif \u22122147483648, et qui ram\u00e8nera donc les horloges au 13 d\u00e9cembre 1901...
Vous pourrez lire sur la page Wikipedia cit\u00e9e plus haut plus d'informations sur ce probl\u00e8me.
"},{"location":"T2_Representation_des_donnees/2.8_Codage_non-entiers/cours/","title":"2.8 Codage des non-entiers","text":"Le principe est l'extension du syst\u00e8me d\u00e9j\u00e0 rencontr\u00e9 pour les nombres entiers. La partie d\u00e9cimale (\u00e0 droite de la virgule) correspondra aux puissances n\u00e9gatives de 2.
... 8 4 2 1 0.5 0.25 0.125 ... ... \\(2^3\\) \\(2^2\\) \\(2^1\\) \\(2^0\\) \\(2^{-1}\\) \\(2^{-2}\\) \\(2^{-3}\\) ... ... 0 1 1 0, 1 0 1 ...Exemple : \\(110,101_2=1 \\times 2^2 + 1 \\times2^1 +0 \\times 2^0 + 1 \\times 2^{-1} +0 \\times 2^{-2}+1 \\times 2^{-2} =4+2+0,5+0,125=6,625\\)
"},{"location":"T2_Representation_des_donnees/2.8_Codage_non-entiers/cours/#1-tentatives-de-conversion","title":"1. Tentatives de conversion","text":""},{"location":"T2_Representation_des_donnees/2.8_Codage_non-entiers/cours/#11-theoreme-de-decomposition-en-puissances-de-2","title":"1.1 Th\u00e9or\u00e8me de d\u00e9composition en puissances de 2","text":"Tout commence bien, avec un r\u00e9sultat math\u00e9matique rassurant : tous les nombres r\u00e9els peuvent s'\u00e9crire comme une somme de puissances de 2 (puissances positives et n\u00e9gatives).
Th\u00e9or\u00e8me
Pour tout r\u00e9el \\(x \\in \\mathbb{R}^+\\), il existe \\(p \\in \\mathbb{N}\\) et \\((a_p,a_{p-1},...,a_0,a_{-1},a_{-2},...)\\) tels que \\(x = \\sum_{i=0}^pa_i2^i+\\sum_{i=1}^{+\\infty}a_{-i}2^{-i}\\)
\u00c9crire un nombre en binaire revient \u00e0 calculer les coefficients \\(a_k\\) (ils sont \u00e9gaux \u00e0 0 ou 1). Il y en a un nombre fini pour la partie enti\u00e8re, mais un nombre potentiellement infini pour la partie d\u00e9cimale.
"},{"location":"T2_Representation_des_donnees/2.8_Codage_non-entiers/cours/#12-methode-de-conversion","title":"1.2 M\u00e9thode de conversion","text":"Consid\u00e9rons le nombre \\(3,6875\\). Il se d\u00e9compose en une partie enti\u00e8re (3) et une partie d\u00e9cimale (\\(0,6875\\)).
On prend ensuite le chiffre des unit\u00e9s de tous les nombres obtenus : 1011
Donc \\(3,6875=11,1011_2\\)
Exercice 1
\u00c9nonc\u00e9CorrectionDonner l'\u00e9criture binaire de 20,875.
Donc \\(20,875=10100,111_2\\)
Exercice 2
\u00c9nonc\u00e9CorrectionDonner l'\u00e9criture binaire de 0,2.
Le nombre 0,2 n'admet pas d'\u00e9criture binaire finie.
"},{"location":"T2_Representation_des_donnees/2.8_Codage_non-entiers/cours/#conclusion","title":"Conclusion","text":"Certains nombres n'admettent pas une \u00e9criture binaire finie. Or la m\u00e9moire d'un ordinateur, quelqu'il soit, est toujours finie. Certains nombres ne peuvent donc pas \u00eatre repr\u00e9sent\u00e9s correctement en machine : c'est une impossibilit\u00e9 th\u00e9orique. Cela am\u00e8ne \u00e0 des comportements \u00e9tranges :
>>> 0.1 + 0.2\n0.30000000000000004\n
Remarque : parmi les nombres d\u00e9cimaux \u00e0 un chiffre apr\u00e8s la virgule (0,1 0,2 0,3 ...) seul 0,5 admet une \u00e9criture binaire finie ! Tous les autres ont une repr\u00e9sentation en machine qui n'en donne qu'une valeur approch\u00e9e.
"},{"location":"T2_Representation_des_donnees/2.8_Codage_non-entiers/cours/#2-consequences-la-difficile-manipulation-des-flottants","title":"2. Cons\u00e9quences : la difficile manipulation des flottants","text":"En python, les nombres non entiers sont du type float.
>>> type(0.1)\n<class 'float'>\n
Ces flottants (traduction fran\u00e7aise) sont \u00e0 manipuler avec une extr\u00eame pr\u00e9caution. Il faut garder en t\u00eate que les calculs sont potentiellement faux, du moins impr\u00e9cis, lorsque des flottants interviennent.
>>> 0.5-0.2-0.2-0.1\n-2.7755575615628914e-17\n
En 1991, durant la Guerre du Golfe, un missile anti-missile am\u00e9ricain a rat\u00e9 sa cible de 500 m\u00e8tres car son ordinateur interne \u00e9mettait un signal toutes les 0.1 secondes. Au bout de 100 heures de fonctionnement, l'approximation du nombre flottant 0.1 a conduit \u00e0 un d\u00e9calage de 0,34 secondes, ce qui lui a fait rater sa cible. (source)
"},{"location":"T2_Representation_des_donnees/2.8_Codage_non-entiers/cours/#3-comment-faire-des-tests-degalite-sur-les-flottants","title":"3. Comment faire des tests d'egalit\u00e9 sur les flottants ?","text":"Premi\u00e8re r\u00e9ponse : ON N'EN FAIT PAS.
Si a
et b
sont deux flottants, le test classique
if a == b :\n print(\"a et b sont \u00e9gaux\")\n
a de grandes chances d'\u00e9chouer :
Le script
a = 0.1\nb = 0.3 - 0.2\nif a == b :\n print(\"a et b sont \u00e9gaux\")\nelse :\n print(\"a et b sont diff\u00e9rents\")\n
renverra
a et b sont diff\u00e9rents\n
Si vraiment un test d'\u00e9galit\u00e9 est n\u00e9cessaire, on ne va pas tester l'\u00e9galit\u00e9 entre a
et b
mais leur proximit\u00e9, gr\u00e2ce \u00e0 la valeur absolue de leur diff\u00e9rence.
La fonction abs(a-b)
renvoie un nombre positif \u00e9gal \u00e0 la distance entre a
et b
. Il faut alors d\u00e9cider d'un \u00e9cart minimal e
en dessous duquel on consid\u00e8rera que a
et b
sont \u00e9gaux.
Le script
a = 0.1\nb = 0.3-0.2\ne = 10**(-12)\nif abs(a-b) < e :\n print(\"a et b sont \u00e9gaux\")\nelse :\n print(\"a et b sont diff\u00e9rents\")\n
renverra
a et b sont \u00e9gaux\n
Exercice
\u00c9nonc\u00e9CorrectionOn consid\u00e8re la fonction \\(f(x)=x^3-6x+2\\). L'\u00e9quation \\(f(x)=1\\) admet une solution unique dans l'intervalle \\([0;1]\\). Trouver une valeur approch\u00e9e de cette solution \u00e0 \\(10^{-5}\\) pr\u00e8s. On prendra e
\\(=0,001\\).
def f(x):\n return x**3 - 6 * x + 2\n\ne = 10**(-3)\na = 0\nwhile abs(f(a) - 1 ) > e :\n a += 10**(-5)\nprint(a)\n
"},{"location":"T2_Representation_des_donnees/2.9_Chaines_caracteres/cours/","title":"2.9 Cha\u00eenes de caract\u00e8res","text":"La manipulation des cha\u00eenes de caract\u00e8res n'est pas au programme, mais quelques astuces sont tr\u00e8s utiles \u00e0 conna\u00eetre.
"},{"location":"T3_Architecture_materielle/sommaire/","title":"Th\u00e8me 3 : Architecture mat\u00e9rielle","text":"BBC micro:bit est une carte \u00e0 microcontr\u00f4leur con\u00e7ue en 2015 au Royaume-Uni pour d\u00e9velopper l'apprentissage de l'algorithmique et de la programmation.
La carte micro:bit dispose des sp\u00e9cificit\u00e9s techniques suivantes :
Rendez-vous sur la page https://create.withcode.uk/
Effacez le code existant et collez-le code ci-dessous :
from microbit import *\n\nwhile True:\n display.scroll('Hello, World!')\n display.show(Image.HEART)\n sleep(2000)\n
Cliquez sur le triangle vert en bas \u00e0 droite. C'est parti !
Pour \u00e9viter des erreurs, fermez la fen\u00eatre de droite (le simulateur) \u00e0 chaque fois que vous modifiez votre code de la partie gauche.
"},{"location":"T3_Architecture_materielle/3.1_Microbit/cours/#12-avec-une-microbit-reelle","title":"1.2 Avec une micro:bit r\u00e9elle","text":"Cette proc\u00e9dure est \u00e0 r\u00e9peter \u00e0 chaque nouveau code.
"},{"location":"T3_Architecture_materielle/3.1_Microbit/cours/#2-decouverte-des-fonctionnalites","title":"2. D\u00e9couverte des fonctionnalit\u00e9s","text":""},{"location":"T3_Architecture_materielle/3.1_Microbit/cours/#21-commandes-de-base-de-lafficheur-matrice-de-5x5-leds","title":"2.1 Commandes de base de l'afficheur, matrice de 5x5 LEDs","text":"voir vid\u00e9o explicative (en anglais)
LED signifie Light Emitting Diode, Diode \u00e9lectroluminescente. La carte micro:bit en dispose de 25, toutes programmables individuellement, ce qui permet d'afficher du texte, des nombres et des images.
"},{"location":"T3_Architecture_materielle/3.1_Microbit/cours/#211-afficher-un-texte-defilant-displayscrollstring-delay400","title":"2.1.1 Afficher un texte \"d\u00e9filant\"display.scroll(string, delay=400)
","text":"from microbit import *\ndisplay.scroll(\"NSI\")\n
La premi\u00e8re ligne de ce programme importe la biblioth\u00e8que de fonctions micro:bit. La deuxi\u00e8me ligne fait d\u00e9filer un message \u00e0 l\u2019\u00e9cran. Cela n'arrive qu'une seule fois.
La vitesse de d\u00e9filement peut \u00eatre ralentie ou acc\u00e9l\u00e9r\u00e9e \u00e0 l'aide du param\u00e8tre delay
. L'unit\u00e9 est la milliseconde.
from microbit import *\ndisplay.scroll(\"mauriac\", delay=20)\n
"},{"location":"T3_Architecture_materielle/3.1_Microbit/cours/#212-afficher-une-image-displayshowimage","title":"2.1.2 Afficher une \"image\" display.show(image)
","text":"Ex\u00e9cuter le programme suivant:
from microbit import *\ndisplay.show(Image.SAD)\n
Liste des images disponibles Image.HEART\nImage.HEART_SMALL\nImage.HAPPY\nImage.SMILE\nImage.SAD\nImage.CONFUSED\nImage.ANGRY\nImage.ASLEEP\nImage.SURPRISED\nImage.SILLY\nImage.FABULOUS\nImage.MEH\nImage.YES\nImage.NO\nImage.CLOCK12\nImage.CLOCK11\nImage.CLOCK10\nImage.CLOCK9\nImage.CLOCK8\nImage.CLOCK7\nImage.CLOCK6\nImage.CLOCK5\nImage.CLOCK4\nImage.CLOCK3\nImage.CLOCK2\nImage.CLOCK1\nImage.ARROW_N\nImage.ARROW_NE\nImage.ARROW_E\nImage.ARROW_SE\nImage.ARROW_S\nImage.ARROW_SW\nImage.ARROW_W\nImage.ARROW_NW\nImage.TRIANGLE\nImage.TRIANGLE_LEFT\nImage.CHESSBOARD\nImage.DIAMOND\nImage.DIAMOND_SMALL\nImage.SQUARE\nImage.SQUARE_SMALL\nImage.RABBIT\nImage.COW\nImage.MUSIC_CROTCHET\nImage.MUSIC_QUAVER\nImage.MUSIC_QUAVERS\nImage.PITCHFORK\nImage.XMAS\nImage.PACMAN\nImage.TARGET\nImage.TSHIRT\nImage.ROLLERSKATE\nImage.DUCK\nImage.HOUSE\nImage.TORTOISE\nImage.BUTTERFLY\nImage.STICKFIGURE\nImage.GHOST\nImage.SWORD\nImage.GIRAFFE\nImage.SKULL\nImage.UMBRELLA\nImage.SNAKE\n
"},{"location":"T3_Architecture_materielle/3.1_Microbit/cours/#creer-sa-propre-image","title":"Cr\u00e9er sa propre image","text":"Chaque pixel LED sur l\u2019affichage physique peut prendre une parmi dix valeurs. Si un pixel prend la valeur 0 c\u2019est qu\u2019il est \u00e9teint. Litt\u00e9ralement, il a une luminosit\u00e9 de z\u00e9ro. En revanche, s\u2019il prend la valeur 9 il est \u00e0 la luminosit\u00e9 maximale. Les valeurs de 1 \u00e0 8 repr\u00e9sentent des niveaux de luminosit\u00e9 entre \u00e9teint (0) et \u00ab au maximum \u00bb (9).
from microbit import *\n\nbateau = Image(\"05050:\"\n \"05050:\"\n \"05050:\"\n \"99999:\"\n \"09990\")\n\ndisplay.show(bateau)\n
Comment dessiner une image? Chaque ligne de l\u2019affichage physique est repr\u00e9sent\u00e9e par une ligne de nombres se terminant par :
et entour\u00e9e de guillemets doubles \"
. Chaque nombre indique une luminosit\u00e9. Il y a cinq lignes de cinq nombres donc il est possible de sp\u00e9cifier la luminosit\u00e9 individuelle de chacune des cinq LED sur chacune des cinq lignes sur l\u2019affichage physique. C\u2019est ainsi que l'on cr\u00e9e une image.
display.set_pixel(x, y, val)
)","text":"Vous pouvez r\u00e9gler la luminosit\u00e9 des pixels de l'affichage individuellement de 0 (d\u00e9sactiv\u00e9) \u00e0 9 (luminosit\u00e9 maximale). Pour des informations sur les coordonn\u00e9es de l'affichage, voir le guide pour matrice \u00e0 LED.
Ex\u00e9cuter le programme suivant:
from microbit import *\ndisplay.set_pixel(1, 4, 9)\n
"},{"location":"T3_Architecture_materielle/3.1_Microbit/cours/#22-boucle-while","title":"2.2 Boucle while
","text":"Le programme suivant utilise une boucle while
pour faire clignoter le pixel central de mani\u00e8re r\u00e9p\u00e9t\u00e9e sur l\u2019\u00e9cran. La boucle while
se r\u00e9p\u00e8te tant que la condition sp\u00e9cifi\u00e9e est vraie (True
). Dans ce cas, nous avons dit que la condition est vraie. Cela cr\u00e9e une boucle infinie.
L'instruction de veille sleep()
provoque la pause du micro:bit pendant un nombre d\u00e9fini de millisecondes choisi entre parenth\u00e8ses.
L'instruction display.clear()
\u00e9teint l'affichage.
Ex\u00e9cuter le programme ci-dessous:
from microbit import *\nwhile True:\n display.set_pixel(2, 2, 9)\n sleep(500)\n display.clear()\n sleep(500)\n
"},{"location":"T3_Architecture_materielle/3.1_Microbit/cours/#avec-un-peu-daleatoire-voir-documentation-sur-le-hasard","title":"Avec un peu d'al\u00e9atoire (voir documentation sur le hasard)","text":"Dans le programme suivant que vous ex\u00e9cuterez, on importe randint
du module random
de MicroPython et on l'utilise pour afficher un pixel au hasard sur la matrice.
from microbit import *\nfrom random import randint\nn=randint(0,4)\np=randint(0,4)\ndisplay.set_pixel(n, p, 9)\n
Tester le programme pr\u00e9c\u00e9dent plusieurs fois de suite. Pour cela, red\u00e9marrer la micro:bit en appuyant sur le bouton RESET
situ\u00e9 \u00e0 l'arri\u00e8re de la carte.
for
","text":"Le programme suivant utilise une boucle for
pour faire d\u00e9filer un pixel sur une ligne. Ex\u00e9cutez-le.
from microbit import *\nwhile True:\n for i in range(5):\n display.set_pixel(i,0,9)\n sleep(200)\n display.clear()\n
"},{"location":"T3_Architecture_materielle/3.1_Microbit/cours/#24-les-entrees-boutons-a-b-et-ab-programmation-evenementielle-video-explicative","title":"2.4 Les entr\u00e9es boutons A, B et A+B - programmation \u00e9v\u00e9nementielle (vid\u00e9o explicative)","text":"Il y a deux boutons sur la face avant du micro:bit (\u00e9tiquet\u00e9s A et B). On peut d\u00e9tecter quand ces boutons sont press\u00e9s, ce qui permet de d\u00e9clencher des instructions sur l'appareil.
Exemples avec le boutton A: - button_a.is_pressed()
: renvoie True si le bouton sp\u00e9cifi\u00e9 est actuellement enfonc\u00e9 et False sinon. - button_a.was_pressed()
: renvoie True ou False pour indiquer si le bouton a \u00e9t\u00e9 appuy\u00e9 depuis le d\u00e9marrage de l'appareil ou la derni\u00e8re fois que cette m\u00e9thode a \u00e9t\u00e9 appel\u00e9e.
Exemple : Essayer le programme suivant qui fait d\u00e9filer le texte \"NSI\" ind\u00e9finiment. On introduit l'instruction conditionnelle if
qui va tester si le bouton A a \u00e9t\u00e9 press\u00e9 (pendant le d\u00e9filement du texte ou pendant la pause), auquel cas le programme s'arr\u00eate en ex\u00e9cutant la commande break
.
from microbit import *\nwhile True:\n display.scroll(\"NSI\")\n sleep(200)\n if button_a.was_pressed():\n break\n
Exercice 1
\u00c9nonc\u00e9CorrectionCr\u00e9er le code permettant de basculer d'un visage triste \u00e0 un visage heureux suivant qu'on appuie sur A ou sur B.
from microbit import *\ndisplay.clear()\nwhile True:\n if button_a.was_pressed():\n display.show(Image.SAD)\n if button_b.was_pressed():\n display.show(Image.HAPPY)\n
Exercice 2
\u00c9nonc\u00e9CorrectionOn veut cr\u00e9er le code permettant de d\u00e9placer un point vers la gauche ou vers la droite en appuyant sur A ou sur B.
Compl\u00e9ter le code propos\u00e9 :
from microbit import *\ndisplay.clear()\ni = 12\nwhile True:\n x = ... # \u00e0 compl\u00e9ter\n y = ... # \u00e0 compl\u00e9ter\n display.set_pixel(x,y,9)\n if button_a.was_pressed():\n display.set_pixel(x,y,0)\n i = i - 1\n if i < 0 : \n i = 0\n if button_b.was_pressed():\n display.set_pixel(x,y,0)\n i = i + 1\n if i > 24 :\n i = 24\n
Exercice 3
\u00c9nonc\u00e9CorrectionCr\u00e9er le code permettant de faire d\u00e9filer toutes les images disponibles. Bouton B pour passer \u00e0 l'image suivante, bouton A pour revenir \u00e0 l'image pr\u00e9c\u00e9dente.
Compl\u00e9ter le code propos\u00e9 :
from microbit import *\n\nlst = [Image.HEART, Image.HEART_SMALL, Image.HAPPY, Image.SMILE,\n Image.SAD, Image.CONFUSED, Image.ANGRY, Image.ASLEEP, Image.SURPRISED, Image.SILLY,\n Image.FABULOUS, Image.MEH, Image.YES, Image.NO, Image.CLOCK12,\n Image.CLOCK11, Image.CLOCK10, Image.CLOCK9, Image.CLOCK8, Image.CLOCK7,\n Image.CLOCK6, Image.CLOCK5, Image.CLOCK4, Image.CLOCK3, Image.CLOCK2,\n Image.CLOCK1, Image.ARROW_N, Image.ARROW_NE, Image.ARROW_E, Image.ARROW_SE,\n Image.ARROW_S, Image.ARROW_SW, Image.ARROW_W, Image.ARROW_NW, Image.TRIANGLE,\n Image.TRIANGLE_LEFT, Image.CHESSBOARD, Image.DIAMOND, Image.DIAMOND_SMALL, Image.SQUARE,\n Image.SQUARE_SMALL, Image.RABBIT, Image.COW, Image.MUSIC_CROTCHET, Image.MUSIC_QUAVER,\n Image.MUSIC_QUAVERS, Image.PITCHFORK, Image.XMAS, Image.PACMAN, Image.TARGET, Image.TSHIRT,\n Image.ROLLERSKATE, Image.DUCK, Image.HOUSE, Image.TORTOISE, Image.BUTTERFLY, Image.STICKFIGURE,\n Image.GHOST, Image.SWORD, Image.GIRAFFE, Image.SKULL, Image.UMBRELLA, Image.SNAKE]\n
"},{"location":"T3_Architecture_materielle/3.1_Microbit/cours/#25-capteur-de-lumiere-video","title":"2.5 Capteur de lumi\u00e8re (vid\u00e9o)","text":"En inversant les LEDs d'un \u00e9cran pour devenir un point d'entr\u00e9e, l'\u00e9cran LED devient un capteur de lumi\u00e8re basique, permettant de d\u00e9tecter la luminosit\u00e9 ambiante.
La commande display.read_light_level()
retourne un entier compris entre 0 et 255 repr\u00e9sentant le niveau de lumi\u00e8re.
Exercice : Compl\u00e9ter le programme ci-dessous qui affiche une image de lune si on baisse la luminosit\u00e9 (en recouvrant la carte avec sa main par exemple) et un soleil sinon.
from microbit import *\n\nsoleil = Image(\"90909:\"\n \"09990:\"\n \"99999:\"\n \"09990:\"\n \"90909:\")\n\nlune = Image(\"00999:\"\n \"09990:\"\n \"09900:\"\n \"09990:\"\n \"00999:\")\n\nwhile True:\n if display.read_light_level()> ... : #trouver la bonne valeur (entre 0 et 255)\n display.show(soleil)\n else:\n display.show(...) #trouver la bonne variable\n sleep(10)\n
Prolongement: cr\u00e9er un programme qui affiche le niveau de luminosit\u00e9 et le tester avec la LED d'un t\u00e9l\u00e9phone portable ou une lampe-torche par exemple. Plus la luminosit\u00e9 sera \u00e9lev\u00e9e, plus il y aura de LEDs affich\u00e9es sur la matrice.
"},{"location":"T3_Architecture_materielle/3.1_Microbit/cours/#26-capteur-de-temperature-video","title":"2.6 Capteur de temp\u00e9rature (vid\u00e9o)","text":"Le micro:bit n\u2019a pas un capteur de temp\u00e9rature d\u00e9di\u00e9. Au lieu de cela, la temp\u00e9rature fournie est en fait la temp\u00e9rature de la puce de silicium du processeur principal. Comme le processeur chauffe peu en fonctionnement (c'est un processeur ARM \u00e0 grande efficacit\u00e9), sa temp\u00e9rature est une bonne approximation de la temp\u00e9rature ambiante. L'instruction temperature()
renvoie la temp\u00e9rature de la carte micro:bit en degr\u00e9s Celsius.
Exercice : Ecrire un programme qui affiche la temp\u00e9rature (aide: on pourra utiliser l'instruction display.scroll()
; revoir le point 2.1.1).
Un acc\u00e9l\u00e9rom\u00e8tre mesure l'acc\u00e9l\u00e9ration de la carte micro:bit, ce composant d\u00e9tecte quand la micro:bit est en mouvement. Il peut aussi d\u00e9tecter d'autres actions (gestes), par exemple quand elle est secou\u00e9e, inclin\u00e9e ou qu'elle tombe.
La carte micro:bit est munie d\u2019un acc\u00e9l\u00e9rom\u00e8tre. Il mesure le mouvement selon trois axes :
Dans l'exemple suivant \u00e0 essayer, l'instruction accelerometer.get_x()
permet de d\u00e9tecter un mouvement de gauche \u00e0 droite en renvoyant un nombre compris entre -1023 et 1023; 0 \u00e9tant la position \"d'\u00e9quilibre\"
#Exemple\nfrom microbit import *\n\nwhile True:\n abscisse = accelerometer.get_x()\n if abscisse > 500:\n display.show(Image.ARROW_E)\n elif abscisse < -500:\n display.show(Image.ARROW_W)\n else:\n display.show(\"-\")\n
Prolongement (secouer les d\u00e9s!):
Exercice 4
\u00c9nonc\u00e9Correction\u00c9crire un programme qui simule un d\u00e9 en affichant une face au hasard lorsque la micro:bit est secou\u00e9e. On pourra utiliser l'instruction accelerometer.is_gesture(shake)
qui teste si la carte est secou\u00e9e. Plus d'informations sur les gestes ici.
La boussole d\u00e9tecte le champ magn\u00e9tique de la Terre, nous permettant de savoir quelle direction la micro:bit indique. La boussole doit \u00eatre \u00e9talonn\u00e9e avant de pouvoir \u00eatre utilis\u00e9e. Pour cela, on utilise compass.calibrate()
qui ex\u00e9cute un petit jeu: au d\u00e9part, micro:bit fait d\u00e9filer \"Tilt to fill screen\". Ensuite, incliner micro:bit pour d\u00e9placer le point au centre de l\u2019\u00e9cran autour jusqu'\u00e0 ce que vous ayez rempli la totalit\u00e9 de l\u2019\u00e9cran.
La fonction compass.heading()
donne le cap de la boussole sous la forme d'un entier compris entre 0 et 360, repr\u00e9sentant l'angle en degr\u00e9s, dans le sens des aiguilles d'une montre, avec le nord \u00e9gal \u00e0 0.
Exercice : Compl\u00e9ter le programme suivant qui indique le Nord.
from microbit import *\n\ncompass.calibrate()\n\nwhile True:\n if compass.heading() < \"remplir ici\" or compass.heading() > \"remplir ici\":\n display.show(Image.ARROW_N)\n else:\n display.show(Image.DIAMOND_SMALL)\n
Prolongement: Am\u00e9liorer le programme pour que le micro:bit indique \"N\", \"S\", \"E\" et \"O\" en fonction de l'orientation de la boussole.
Autre prolongement: fabriquer une station m\u00e9t\u00e9o qui d\u00e9termine la direction du vent.
Autre prolongement: \u00e9tudier l'intensit\u00e9 du champ magn\u00e9tique autour du p\u00e9riph\u00e9rique (en utilisant la fonction compass.get_field_strength()
). Plus d'informations sur les fonctions \"boussole\" ici.
document bas\u00e9 sur le travail de Thomas Basso, acad\u00e9mie de Polyn\u00e9sie
"},{"location":"T3_Architecture_materielle/3.2_Architecture_Von_Neumann/cours/","title":"3.2 Architecture Von Neumann","text":"John Von Neumann (1903-1957) est un math\u00e9maticien et physicien (et bien d'autres choses) am\u00e9ricano-hongrois. Il a le premier th\u00e9oris\u00e9 l'architecture des processeurs, tels qu'ils fonctionnent encore aujourd'hui.
"},{"location":"T3_Architecture_materielle/3.2_Architecture_Von_Neumann/cours/#1-architecture-von-neumann","title":"1. Architecture von Neumann","text":"On distingue 4 zones essentielles :
Cette activit\u00e9 est disponible ici en vid\u00e9o.
"},{"location":"T3_Architecture_materielle/3.2_Architecture_Von_Neumann/cours/#21-le-programme-que-nous-etudierons","title":"2.1 Le programme que nous \u00e9tudierons","text":"a = 3\nb = 5\nc = a + b\n
Ce programme est ici \u00e9crit en langage Python. Le processeur ne comprend pas ce langage : les instructions doivent lui \u00eatre pass\u00e9es en langage-machine. C'est le r\u00f4le des interpr\u00e9teurs (pour le Python, par exemple) ou des compilateurs (pour le C, par exemple) que de faire le lien entre le langage pratiqu\u00e9 par les humains (Python, C...) et le langage-machine, qui n'est qu'une succession de chiffres binaires.
Par exemple, notre code ci-dessus s'\u00e9crit
01010000 00001111 00011000 00000000\n00000000 00000000 01010000 00111111\n00011100 00000000 00000000 00000000\n01100000 00000011 01000000 00111111\n00100000 00000000 00000000 00000000\n00000000 00000000 00000000 00000000\n00000011 00000000 00000000 00000000\n00000101 00000000 00000000 00000000\n
en langage-machine. Comment a lieu cette transformation ?
"},{"location":"T3_Architecture_materielle/3.2_Architecture_Von_Neumann/cours/#22-au-plus-proche-de-la-machine-mais-encore-humainement-comprehensible-le-langage-assembleur","title":"2.2 Au plus proche de la machine mais encore humainement compr\u00e9hensible : le langage assembleur","text":"Il existe un langage dit de \"bas-niveau\" (au sens qu'il est plus proche du langage machine qu'un langage de haut-niveau comme le Python) qui permet de passer des instructions directement au processeur : c'est le langage assembleur (ou ASM).
En assembleur, notre programme s'\u00e9crirait (par exemple) :
.pos 0\n mrmovl a, %eax\n mrmovl b, %ebx\n addl %eax, %ebx\n rmmovl %ebx, c\n halt\n\n.align 4\na: .long 3\nb: .long 5\nc: .long 0 \n
Le simulateur Y86 permet de simuler la mani\u00e8re dont le processeur va ex\u00e9cuter ce programme.
Vous pouvez retrouver le programme \u00e0 charger ici.
Sur la partie droite du simulateur, la zone M\u00e9moire contient, apr\u00e8s assemblage, la traduction de notre code en langage-machine :
500f1800\n0000503f\n1c000000\n6003403f\n20000000\n00000000\n03000000\n05000000\n
Une fois transform\u00e9 en binaire, on retrouve le code donn\u00e9 au d\u00e9but du paragraphe pr\u00e9c\u00e9dent.
Ressources sur les instructions Y86
Exercice
\u00c9nonc\u00e9CorrectionCoder en assembleur la s\u00e9quence d'instruction suivante :
w = 10\nx = 3\ny = 5\nz = w - (x + y)\n
Vous aurez pour cela besoin de l'instruction subl rA rB
qui effectue l'op\u00e9ration rB-rA
et la stocke dans rB
. (rA
et rB
sont les noms des registres).
.pos 0\nmrmovl x, %eax\nmrmovl y, %ebx\nmrmovl w, %ecx\naddl %eax, %ebx\nsubl %ebx, %ecx\nrmmovl %ecx, z\nhalt\n\n.align 4\nw: .long 10\nx: .long 3\ny: .long 5\nz: .long 0\n
"},{"location":"T3_Architecture_materielle/3.2_Architecture_Von_Neumann/cours/#24-resume-des-notions-essentielles","title":"2.4 R\u00e9sum\u00e9 des notions essentielles","text":"03
situ\u00e9 \u00e0 l'adresse 0x000d
signifie qu'il va falloir ajouter (on le sait gr\u00e2ce au 60
qui pr\u00e9c\u00e8de) le registre num\u00e9rot\u00e9 0
(donc %eax
) au registre num\u00e9rot\u00e9 3
(donc %ebx
). On retrouve un octet de m\u00eame valeur 03
\u00e0 l'adresse 0x0018
. Mais dans ce cas, cet octet n'est pas une instruction mais une simple donn\u00e9e : c'est la valeur 3 qu'on a donn\u00e9e \u00e0 la variable a
dans notre programme. Le simulateur Y86 nous a permis d'observer comment un processeur r\u00e9alise des op\u00e9rations \u00e9l\u00e9mentaires. Nous avons d\u00e9couvert le langage assembleur, qui est un langage beaucoup moins agr\u00e9able qu'un langage de haut-niveau, mais qui reste n\u00e9anmoins compr\u00e9hensible par un \u00eatre humain. Certains informaticiens codent (encore de nos jours) directement en langage assembleur, pour \"coller\" au mieux au processeur et optimiser les ressources.
"},{"location":"T3_Architecture_materielle/3.2_Architecture_Von_Neumann/cours/#3-activite-2-modification-dun-programme-par-desassemblage","title":"3. Activit\u00e9 2 : modification d'un programme par d\u00e9sassemblage","text":"On consid\u00e8re ci-dessous le programme crackme.c
, r\u00e9dig\u00e9 en langage en C. Vous pouvez t\u00e9l\u00e9charger ce programme ici.
#include \"stdio.h\"\n#include \"stdlib.h\"\n#include \"string.h\"\n\nint main()\n{\n\nchar saisie[50] = \"\";\nprintf(\"Acc\u00e8s restreint : saisissez votre mot de passe \\n\");\nwhile (strcmp(saisie,\"NSIMAURIAC\")!=0)\n{\nprintf(\"Mot de passe ? \\n\");\nscanf(\"%s\",&saisie);\n}\n\nprintf(\"Acc\u00e8s autoris\u00e9 \\n\");\n\nreturn 0;\n}
gcc crackme.c -o crackme
./crackme
et jouez avec le programme.\u00c0 l'aide du programme GHex , il est possible d'aller observer la valeur des octets directement dans le fichier binaire crackme
.
Ce fichier binaire est \u00e9crit en langage-machine. Il est donc incompr\u00e9hensible pour un autre humain... m\u00eame si GHex nous aide en affichant notamment (dans la partie droite) les cha\u00eenes de caract\u00e8res... dont notre mot de passe ;)
"},{"location":"T3_Architecture_materielle/3.2_Architecture_Von_Neumann/cours/#33-modification-du-fichier-binaire","title":"3.3 Modification du fichier binaire","text":"Dans notre code C l'instruction while (strcmp(saisie,\"NSIMAURIAC\")!=0)
est le c\u0153ur de la v\u00e9rification du mot de passe. En assembleur, elle va donner naissance \u00e0 une instruction JNE
(pour Jump if Not Equal, voir ici ). Cette instruction est cod\u00e9e en hexad\u00e9cimal par l'opcode 75 C5
. Nous allons rechercher ces octets et les remplacer par 90 90
, 90
\u00e9tant l'opcode pour NOP
(ne rien faire).
75 C5
.90 90
.crackme2
. Vous pouvez sinon le t\u00e9l\u00e9charger ici sudo chmod 777 crackme2
Le d\u00e9sassemblage d'un programme est une op\u00e9ration tr\u00e8s complexe et les op\u00e9rations et cha\u00eenes de caract\u00e8res qui apparaissent sont souvent incompr\u00e9hensibles (parfois volontairement, dans le cas d'obfuscation de code). N\u00e9anmoins, il est parfois possible d'agir au niveau le plus bas (le langage-machine) pour modifier un code, comme nous venons de le faire.
BibliographieCe cours a pour but de pr\u00e9senter la constitution classique d'un r\u00e9seau, et les \u00e9quipements associ\u00e9s. La partie relative aux protocoles utilis\u00e9s lors des \u00e9changes entre deux machines est d\u00e9taill\u00e9e dans le cours sur les protocoles de communication.
"},{"location":"T3_Architecture_materielle/3.3_Architecture_reseau/cours/#1-premier-reseau-local","title":"1. Premier r\u00e9seau local","text":"lien de t\u00e9l\u00e9chargement de Filius sous Linux
Au sein du logiciel Filius, cr\u00e9ons le r\u00e9seau local ci-dessous :
Testons le ping
de la machine 192.168.0.1
vers la machine 192.168.0.3
.
Chaque ordinateur sur le r\u00e9seau dispose d'une adresse MAC, qui une valeur unique attribu\u00e9e \u00e0 sa carte r\u00e9seau (Ethernet, Wifi, 4G, 5G, ...) lors de sa fabrication en usine.
Cette adresse est cod\u00e9e sur 48 bits, pr\u00e9sent\u00e9s sous la forme de 6 octets en hexad\u00e9cimal. Exemple : fc:aa:14:75:45:a5
Les trois premiers octets correspondent au code du fabricant. Un site comme https://www.macvendorlookup.com/ vous permet de retrouver le fabricant d'une adresse MAC quelconque.
"},{"location":"T3_Architecture_materielle/3.3_Architecture_reseau/cours/#12-switch-hub-quelle-difference","title":"1.2. Switch, hub, quelle diff\u00e9rence ?","text":"Rajoutons un deuxi\u00e8me sous-r\u00e9seau de la mani\u00e8re suivante (penser \u00e0 bien renommer les switchs).
Comment relier ces deux sous-r\u00e9seaux ?
Une r\u00e9ponse pas si b\u00eate : avec un cable entre les deux switchs !
Testons cette hypoth\u00e8se en essayant de pinger la machine 192.168.1.2
depuis la machine 192.168.0.1
.
Cela ne marche pas. L'ordinateur refuse d'envoyer le ping vers la machine 192.168.1.2
. (spoil : car elle n'est pas dans son sous-r\u00e9seau)
Temporairement, renommons la machine 192.168.1.2
en 192.168.0.33
. Testons \u00e0 nouveau le ping depuis la machine 192.168.0.1
.
Cela marche. Les paquets sont bien achemin\u00e9s.
Intuition : la notion de sous-r\u00e9seau n'est pas topologique (\u00abil suffit de relier les ordinateurs entre eux\u00bb) mais ob\u00e9it \u00e0 des r\u00e8gles num\u00e9riques.
"},{"location":"T3_Architecture_materielle/3.3_Architecture_reseau/cours/#21-notion-de-masque-de-sous-reseau","title":"2.1. Notion de masque de sous-r\u00e9seau","text":"Dans Filius, lors de l'attribution de l'adresse IP \u00e0 une machine, une ligne nous permet de sp\u00e9cifier le masque de sous-r\u00e9seau (appel\u00e9 simplement \u00ab Masque \u00bb dans Filius). C'est ce masque qui va permettre de d\u00e9terminer si une machine appartient \u00e0 un sous-r\u00e9seau ou non, en fonction de son adresse IP.
"},{"location":"T3_Architecture_materielle/3.3_Architecture_reseau/cours/#211-explication-basique","title":"2.1.1 Explication basique","text":"255.255.255.0
, toutes les machines partageant les m\u00eames trois premiers nombres de leur adresse IP appartiendront au m\u00eame sous-r\u00e9seau. Comme ceci est le r\u00e9glage par d\u00e9faut de Filius, cela explique pourquoi 192.168.0.33
et 192.168.0.1
sont sur le m\u00eame sous-r\u00e9seau, et pourquoi 192.168.1.2
et 192.168.0.1
ne sont pas sur le m\u00eame sous-r\u00e9seau.Dans cette configuration, 256 machines peuvent donc appartenir au m\u00eame sous-r\u00e9seau (ce n'est pas tout \u00e0 fait le cas car des adresses finissant par 0 ou par 255 sont r\u00e9serv\u00e9es).
255.255.0.0
, toutes les machines partageant les m\u00eames deux premiers nombres de leur adresse IP appartiendront au m\u00eame sous-r\u00e9seau. Dans cette configuration, 65536 machines peuvent \u00eatre dans le m\u00eame sous-r\u00e9seau. (car 256^2=65536)Exercice
192.168.0.33
en 192.168.1.2
et modifions son masque en 255.255.0.0
.192.168.0.1
en 255.255.0.0
.192.168.0.1
vers 192.168.1.2
.Cela marche. Les deux machines appartiennent maintenant au m\u00eame sous-r\u00e9seau.
"},{"location":"T3_Architecture_materielle/3.3_Architecture_reseau/cours/#212-explication-avancee","title":"2.1.2 Explication avanc\u00e9e","text":"Lorsqu'une machine A veut envoyer un message \u00e0 une machine B, elle doit d\u00e9terminer si cette machine :
Quelle op\u00e9ration permet de distinguer cette appartenance \u00e0 un m\u00eame sous-r\u00e9seau ?
Appelons IP_A
et IP_B
les adresses IP respectives des machines A et B. Appelons M
le masque de sous-r\u00e9seau. Nommons &
l'op\u00e9rateur de conjonction entre nombres binaires (voir ici):
Propri\u00e9t\u00e9 : A et B appartiennent au m\u00eame sous-r\u00e9seau \u21d4 IP_A & M = IP_B & M
Exemple : consid\u00e9rons trois machines A, B, C d'IP respectives 192.168.129.10
, 192.168.135.200
et 192.168.145.1
, configur\u00e9es avec un masque de sous-r\u00e9seau \u00e9gal \u00e0 255.255.248.0
.
rappel des r\u00e8gles de calcul :
x
, x & 255 = x
et x & 0 = 0
.129 & 248
s'\u00e9crit en binaire 10000001 & 11111000
qui vaut 10000000
, soit 128
en d\u00e9cimal.Conclusion : les machines A et B sont sous le m\u00eame sous-r\u00e9seau, mais pas la machine C.
"},{"location":"T3_Architecture_materielle/3.3_Architecture_reseau/cours/#213-coherence-entre-les-deux-explications","title":"2.1.3 Coh\u00e9rence entre les deux explications","text":"Lorsqu'un masque de sous-r\u00e9seau est \u00e9gal \u00e0 255.255.255.0
, l'op\u00e9ration de conjonction &
avec chaque IP ne laissera intacts que les 3 premiers octets, le dernier sera \u00e9gal \u00e0 0. Donc si deux adresses s'\u00e9crivent A.B.C.X
et A.B.C.Y
, elles appartiendront forc\u00e9ment au m\u00eame sous-r\u00e9seau (typiquement, c'est le cas de 192.168.0.33
et 192.168.0.1
).
D'apr\u00e8s ce qui pr\u00e9c\u00e8de, 2 informations sont n\u00e9cessaires pour d\u00e9terminer le sous-r\u00e9seau auquel appartient une machine : son IP et le masque de sous-r\u00e9seau. Une convention de notation permet d'\u00e9crire simplement ces deux renseignements : la notation CIDR.
Exemple : Une machine d'IP 192.168.0.33
avec un masque de sous-r\u00e9seau 255.255.255.0
sera d\u00e9sign\u00e9e par 192.168.0.33 / 24
en notation CIDR.
Le suffixe / 24
signifie que le masque de sous-r\u00e9seau commence par 24 bits cons\u00e9cutifs de valeur 1 : le reste des bits (donc 8 bits) est \u00e0 mis \u00e0 0. Autrement dit, ce masque vaut 11111111.11111111.11111111.00000000
, soit 255.255.255.0
. De la m\u00eame mani\u00e8re, le suffixe / 16
donnera un masque de 11111111.11111111.00000000.00000000
, soit 255.255.0.0
. Ou encore, un suffixe / 21
donnera un masque de 11111111.11111111.11111000.00000000
, soit 255.255.248.0
.
D\u00e9finition
0.0.0.0
\u00e0 255.255.255.255
.Exemple
"},{"location":"T3_Architecture_materielle/3.3_Architecture_reseau/cours/#3-un-vrai-reseau-contenant-deux-sous-reseaux-distincts-la-necessite-dun-routeur","title":"3. Un vrai r\u00e9seau contenant deux sous-r\u00e9seaux distincts : la n\u00e9cessit\u00e9 d'un routeur","text":"Notre solution initiale (relier les deux switchs par un cable pour unifier les deux sous-r\u00e9seaux) n'est pas viable \u00e0 l'\u00e9chelle d'un r\u00e9seau plan\u00e9taire.
Pour que les machines de deux r\u00e9seaux diff\u00e9rents puissent \u00eatre connect\u00e9es, on va utiliser un dispositif \u00e9quip\u00e9 de deux cartes r\u00e9seaux, situ\u00e9 \u00e0 cheval entre les deux sous-r\u00e9seaux. Ce \u00e9quipement de r\u00e9seau est appel\u00e9 routeur ou passerelle.
"},{"location":"T3_Architecture_materielle/3.3_Architecture_reseau/cours/#31-principe-de-fonctionnement","title":"3.1 Principe de fonctionnement","text":"Imaginons que la machine 192.168.0.1 / 24
veuille communiquer avec la machine 172.16.52.3 / 24
. L'observation du masque de sous-r\u00e9seau de la machine 192.168.0.1 / 24
nous apprend qu'elle ne peut communiquer qu'avec les adresses de la forme 192.168.0.X / 24
, o\u00f9 X
est un nombre entre 0 et 255.
Les 3 \u00e9tapes du routage :
Dans notre exemple, l'adresse 172.16.52.3
n'est pas dans le sous-r\u00e9seau de 192.168.0.1
. Le message va donc transiter par le routeur.
Rajoutons un routeur entre le SwitchA et le SwitchB.
Configuration du routeur : L'interface reli\u00e9e au Switch A doit avoir une adresse du sous-r\u00e9seau A. On donne souvent une adresse finissant par 254
, qui est en quelque sorte la derni\u00e8re adresse du r\u00e9seau (en effet l'adresse en 255
est appel\u00e9e adresse de broadcast, utilis\u00e9e pour pinger en une seule fois l'int\u00e9gralit\u00e9 d'un sous-r\u00e9seau). On donne donc l'adresse 192.168.0.254
pour l'interface reli\u00e9e au Switch A, et 192.168.1.254
pour l'interface reli\u00e9e au Switch B. Dans l'onglet g\u00e9n\u00e9ral, s\u00e9lectionner \u00ab Routage automatique \u00bb. Ainsi configur\u00e9 notre routeur peut jouer le r\u00f4le de passerelle entre les deux sous-r\u00e9seaux.
192.168.0.1
et 192.168.1.2
Cela ne marche pas. La carte r\u00e9seau refuse d'envoyer les paquets car elle ne sait pas o\u00f9 les envoyer.
Pourquoi cet \u00e9chec ? Parce que nous devons dire \u00e0 chaque machine qu'une passerelle est maintenant disponible pour pouvoir sortir de son propre sous-r\u00e9seau. Il faut donc aller sur la machine 192.168.0.1
et lui donner l'adresse de sa passerelle, qui est 192.168.0.254
.
Attention, il faut faire de m\u00eame pour 192.168.1.2
(avec la bonne passerelle...) Testons \u00e0 nouveau le ping... Cette fois cela marche.
Plus int\u00e9ressant : effectuons un traceroute
entre 192.168.0.1
et 192.168.1.2
.
On y aper\u00e7oit que la machine 192.168.1.2
est atteignable en deux sauts depuis 192.168.0.1
, en passant par la passerelle 192.168.0.254
Cas d'un r\u00e9seau domestique
Chez vous, la box de votre op\u00e9rateur joue simultan\u00e9ment le r\u00f4le de switch et de routeur :
L'image ci-dessous pr\u00e9sente le r\u00e9sultat de la commande ipconfig
sous Windows. On y retrouve l'adresse IP locale 192.168.9.103
, le masque de sous-r\u00e9seau 255.255.255.0
et l'adresse de la passerelle 192.168.9.1
.
Connectons un ordinateur au SwitchB, sur l'adresse 192.168.1.30
et installons dessus un Serveur web et d\u00e9marrons-le.
Sur la machine 192.168.0.1
, rajoutons un Navigateur Web. En tapant dans la barre d'adresse l'adresse IP du Serveur web, la page d'accueil de Filius s'affiche.
Lors d'une utilisation classique d'un navigateur web, c'est une url m\u00e9morisable qui s'affiche, et non une adresse IP : on retient en effet plus facilement https://www.google.com/
que http://216.58.213.131
, qui renvoient pourtant \u00e0 la m\u00eame adresse. La machine qui assure ce r\u00f4le d'annuaire entre les serveurs web et leur adresse IP s'appelle un serveur DNS. Pour pouvoir indexer la totalit\u00e9 des sites internet, son r\u00f4le est structur\u00e9 de mani\u00e8re hi\u00e9rarchique. Vous trouverez des d\u00e9tails ici
Sur ce serveur DNS, associons l'adresse http://www.vivelansi.fr
\u00e0 l'adresse IP 192.168.1.30
.
De retour sur notre machine 192.168.0.1
, sp\u00e9cifions maintenant l'adresse du serveur DNS :
Depuis le navigateur web de la machine 192.168.0.1
, le site http://www.vivelansi.fr
est maintenant accessible.
Bibliographie
Les bits transmis d'un ordinateur \u00e0 un autre contiennent, en plus des donn\u00e9es utiles (le mot \u00abbonjour\u00bb dans un email), une multitude de donn\u00e9es (tout aussi utiles) qui vont aider \u00e0 l'acheminement de ces bits au bon endroit, puis au bon ordinateur, puis au bon logiciel. Les diff\u00e9rents protocoles qui r\u00e9gissent cette transmission sont regroup\u00e9s dans ce qui est appel\u00e9 un mod\u00e8le. Deux mod\u00e8les synth\u00e9tisent ces protocoles :
Ces deux mod\u00e8les co\u00efncident suivant le sch\u00e9ma ci-dessus. Ce sont des mod\u00e8les th\u00e9oriques et d'une certaine rigidit\u00e9. Leur utilisation dans la pratique est parfois plus floue, avec des protocoles \u00e0 cheval sur plusieurs couches. Dans la suite de ce cours, nous \u00e9voquerons les couches par leur num\u00e9ro dans le mod\u00e8le OSI.
Lors de son \u00e9mission, un message va subir successivement toutes les transformations effectu\u00e9es par chaque couche, depuis sa cr\u00e9ation (couche 7) jusqu'\u00e0 sa transmission physique (couche 1).
Lorsque ce m\u00eame message sera r\u00e9ceptionn\u00e9, les transformations seront effectu\u00e9es dans l'ordre inverse, jusqu'\u00e0 la pr\u00e9sentation du message au destinataire.
couches 7-6-5 \u2014 couches application-pr\u00e9sentation-session : Ces couches (r\u00e9unies dans le mod\u00e8le Internet en une couche unique \u00abapplication\u00bb ) regroupent les protocoles n\u00e9cessaires \u00e0 la bonne mise en forme d'un message (au sens large) avant sa transmission. Ces protocoles peuvent \u00eatre de nature tr\u00e8s diff\u00e9rente : protocole HTTP pour la transmisson de pages web, protocole FTP pour le transfert de fichiers, protocoles POP ou IMAP pour le courrier \u00e9lectronique...
couche 4 \u2014 couche transport : Le protocole majeur de cette couche est le protocole TCP :
couche 3 \u2014 couche r\u00e9seau : C'est la couche o\u00f9 chaque segment num\u00e9rot\u00e9 est encapsul\u00e9 dans un paquet qui, suivant le protocole IP, va contenir son adresse source et son adresse de destination. C'est \u00e0 ce niveau que se d\u00e9cide si le message doit rester dans le r\u00e9seau local ou \u00eatre envoy\u00e9 sur un autre r\u00e9seau via la passerelle du routeur. Les \u00e9l\u00e9ments \u00e9chang\u00e9s avec la couche inf\u00e9rieure sont des paquets.
couche 2 \u2014 couche liaison : C'est l'encapsulation finale du message. Suivant le protocole Ethernet, les informations sont transmises d'une carte r\u00e9seau \u00e0 une autre, gr\u00e2ce \u00e0 leur adresse MAC (Media Access Controler). Les \u00e9l\u00e9ments \u00e9chang\u00e9s avec la couche inf\u00e9rieure sont des trames.
couche 1 \u2014 couche physique : C'est la couche o\u00f9 le message est transmis physiquement d'un point \u00e0 un autre. Par signal lumineux (fibre optique), par ondes (wifi), par courant \u00e9lectrique (Ethernet)... Les \u00e9l\u00e9ments transmis sont les bits.
Lors de son parcours, une trame peut \u00eatre partiellement d\u00e9capsul\u00e9e et remonter \u00e0 la couche 3, avant de redescendre et de continuer son chemin. C'est le cas notamment lors du passage dans un routeur. Mais jamais, lors de son acheminement, le contenu r\u00e9el du message n'est ouvert : les paquets transmis sont achemin\u00e9s de mani\u00e8re identique, qu'ils contiennent les \u00e9l\u00e9ments constitutifs d'une vid\u00e9o YouTube ou d'un email \u00e0 votre cousin.
Ce principe fondateur, actuellement menac\u00e9 par certains acteurs politiques et industriels, est connu sous l'expression \u00abla neutralit\u00e9 du net\u00bb.
"},{"location":"T3_Architecture_materielle/3.4_Protocoles_de_communication/cours/#2-observation-des-trames-avec-filius","title":"2. Observation des trames avec Filius","text":""},{"location":"T3_Architecture_materielle/3.4_Protocoles_de_communication/cours/#21-ping-a-travers-un-switch","title":"2.1. Ping \u00e0 travers un switch","text":"Vous pouvez t\u00e9l\u00e9charger le fichier ping_switch.fls.
192.168.0.10
d'adresse MAC BC:81:81:42:9C:31
\u00e0 une machine 192.168.0.11
d'adresse MAC 2A:AB:AC:27:D6:A7
\u00e0 travers un switch.
192.168.0.10
vers 192.168.0.11
et observons les donn\u00e9es \u00e9chang\u00e9es :
Cette premi\u00e8re ligne est une requ\u00eate ARP. ARP est un protocole qui s'interface entre la couche 3 / r\u00e9seau (appel\u00e9e dans la capture d'\u00e9cran Internet) et la couche 2 / liaison (appel\u00e9e dans la capture d'\u00e9cran R\u00e9seau). Comme indiqu\u00e9 dans le commentaire, elle consiste \u00e0 un appel \u00e0 tout le r\u00e9seau : \"Est-ce que quelqu'un ici poss\u00e8de l'IP 192.168.0.11
?
Message 1 : \u00ab Qui poss\u00e8de l'IP 192.168.0.11
? \u00bb
Il faut comprendre \u00e0 cette \u00e9tape que l'adresse IP est totalement inutile pour r\u00e9p\u00e9rer un ordinateur dans un sous-r\u00e9seau. Ce sont les adresses MAC qui permettent de se rep\u00e9rer dans un sous-r\u00e9seau. Les adresses IP, elles, permettront \u00e9ventuellement d'acheminer le message jusqu'au bon sous-r\u00e9seau (elles n'int\u00e9ressent donc que les routeurs).
Revenons \u00e0 notre ping vers 192.168.0.11
.
La commande arp -a
effectu\u00e9e dans un terminal de la machine 192.168.0.10
nous permet de voir qu'elle ne conna\u00eet encore personne dans son sous-r\u00e9seau. La table de correspondance IP \u2b80 MAC ne contient que l'adresse de broadcast 255.255.255.255
, qui permet d'envoyer un message \u00e0 tout le r\u00e9seau.
Constatant qu'elle ne sait pas quelle est l'adresse MAC de 192.168.0.11
, la machine 192.168.0.10
commence donc par envoyer un message \u00e0 tout le sous-r\u00e9seau, par l'adresse MAC de broadcast FF:FF:FF:FF:FF:FF
. Le switch va lui aussi lui aussi relayer ce message \u00e0 tous les \u00e9quipements qui lui sont connect\u00e9s (dans notre cas, un seul ordinateur)
Message 2 : \u00ab Moi ! \u00bb
La machine 192.168.0.11
s'est reconnu dans le message de broadcast de la machine 192.168.0.10
. Elle lui r\u00e9pond pour lui donner son adresse MAC.
\u00c0 partir de ce moment, la machine 192.168.0.10
sait comment communiquer avec 192.168.0.11
. Elle l'\u00e9crit dans sa table arp
, afin de ne plus avoir \u00e0 \u00e9mettre le message n\u00b01 :
Le switch, qui a vu passer sur ses ports 0 et 1 des messages venant des cartes MAC BC:81:81:42:9C:31
et 2A:AB:AC:27:D6:A7
, peut mettre \u00e0 jour sa table SAT :
Par la suite, il saura sur quel port rediriger les messages destin\u00e9s \u00e0 ces deux adresses MAC. Un switch est un \u00e9quipement de r\u00e9seau de la couche 2 du mod\u00e8le OSI, il ne sait pas lire les adresses IP : il ne travaille qu'avec les adresses MAC.
Message 3 : le ping est envoy\u00e9
Sch\u00e9matisons cette trame Ethernet (couche 2 du mod\u00e8le OSI) :
Message 4 : le pong est retourn\u00e9
"},{"location":"T3_Architecture_materielle/3.4_Protocoles_de_communication/cours/#22-ping-a-travers-un-routeur","title":"2.2. Ping \u00e0 travers un routeur","text":"
Vous pouvez t\u00e9l\u00e9charger le fichier ping_routeur.fls.
L'objectif est d'observer les diff\u00e9rentes trames lors d'un ping entre :
192.168.0.1 / 24
(adresse MAC F9:E1:D6:0B:29:03
) et192.168.1.1 / 24
(adresse MAC D3:79:96:B8:5C:A4
)Le routeur est configur\u00e9 ainsi :
192.168.0.254
77:C2:22:C9:5C:E7
192.168.1.254
66:E5:4E:7D:0B:B0
\u00c9tape 0 : le routeur signale sa pr\u00e9sence
Lors de l'observation des messages re\u00e7us ou \u00e9mis par la machine 192.168.0.1
, on peut \u00eatre intrigu\u00e9 par ce tout premier message re\u00e7u, \u00e9mis par le routeur :
On peut y distinguer les 4 couches du mod\u00e8le Internet. Le routeur, par ce message distribu\u00e9 \u00e0 tous les \u00e9l\u00e9ments du sous-r\u00e9seau A (il envoie un message \u00e9quivalent sur son sous-r\u00e9seau B), d\u00e9clare sa pr\u00e9sence, et le fait qu'il poss\u00e8de deux interfaces, une pour chaque r\u00e9seau. Il se positionne ainsi comme une passerelle : \u00abc'est par moi qu'il faudra passer si vous voulez sortir de votre sous-r\u00e9seau\u00bb. Dans cette trame envoy\u00e9e figure son adresse MAC, de sorte que tous les membres de son sous-r\u00e9seau pourront donc communiquer avec lui.
\u00c9tape 1 : de 192.168.0.1
vers le routeur
La machine 192.168.0.1 / 24
calcule que la machine 192.168.1.1 / 24
avec laquelle elle veut communiquer n'est pas dans son sous-r\u00e9seau. Elle va donc envoyer son message \u00e0 sa passerelle, qui est l'adresse du routeur dans son sous-r\u00e9seau.
Cette premi\u00e8re trame est :
\u00c9tape 2 : le routeur d\u00e9capsule la trame
Le routeur est un \u00e9quipement de r\u00e9seau de couche 3 (couche r\u00e9seau). Il doit observer le contenu du paquet IP (sans remonter jusqu'au contenu du message) pour savoir, suivant le proc\u00e9d\u00e9 de routage (voir cours de Terminale), o\u00f9 acheminer ce paquet.
Dans notre cas, l'adresse IP 192.168.1.1
de destination lui est accessible : elle fait partie de son sous-r\u00e9seau B.
Le routeur va modifier la valeur du TTL (Time To Live), en la d\u00e9cr\u00e9mentant de 1. Si, apr\u00e8s de multiples routages, cette valeur devenait \u00e9gale \u00e0 0, ce paquet serait d\u00e9truit. Ceci a pour but d'\u00e9viter l'encombrement des r\u00e9seaux avec des paquets ne trouvant pas leur destination.
NAT : translation d'adresseDans notre cas, le routeur va laisser intacte l'adresse IP Source. Ce n'est pas toujours le cas. Dans le cas classique de la box qui relie votre domicile \u00e0 internet, le routeur contenu dans celle-ci va remplacer l'adresse locale de votre ordinateur ou smartphone (ex 192.168.0.26
) par son IP publique (celle apparaissant sur whatsmyip.com, par exemple). Elle effectue ce qu'on appelle une translation d'adresse (NAT). Pourquoi ? Parce que sinon la r\u00e9ponse du serveur distant que vous interrogez serait envoy\u00e9e sur une adresse locale (votre adresse 192.168.0.26
), qui est introuvable depuis un r\u00e9seau ext\u00e9rieur. Il faut donc remplacer toutes les adresses locales par l'IP publique de votre box. Pour \u00e9viter que la r\u00e9ponse du serveur web que vous avez interrog\u00e9 ne soit affich\u00e9e sur l'ordinateur de vos parents, le routeur affecte des ports diff\u00e9rents \u00e0 chaque machine de son sous-r\u00e9seau. Ce port est inclus dans le message transmis au serveur, et il l'est aussi dans sa r\u00e9ponse : le routeur peut donc rediriger le trafic vers la bonne machine du sous-r\u00e9seau.
Le routeur va r\u00e9-encapsuler le paquet IP modifi\u00e9, et cr\u00e9er une nouvelle trame Ethernet en modifiant :
192.168.1.1
(qu'il aura peut-\u00eatre r\u00e9cup\u00e9r\u00e9e au pr\u00e9alable par le protocole ARP)Cette deuxi\u00e8me trame est donc :
On peut observer dans Filius cette trame, en se positionnant sur l'interface 192.168.1.254
du routeur, ou sur 192.168.1.1
:
En suivant le m\u00eame principe, la machine 192.168.1.1
pourra envoyer son pong.
Exercice de bac
\u00c9nonc\u00e9CorrectionParties 2 et 3 de l'exercice 2 du sujet Nouvelle-Cal\u00e9donie J1 2022.
Partie 2
Correction Q1.Le r\u00e9seau services a pour adresse IP 195.168.254.0
.
Le r\u00e9seau services a pour adresse 195.168.254.0
. Comme le masque de sous-r\u00e9seau utilis\u00e9 est 255.255.255.0
, 254 adresses sont initialement disponibles (195.168.254.1
\u00e0 195.168.254.254
, puisque l'adresse 195.168.254.255
est r\u00e9serv\u00e9e pour le broadcast sur le r\u00e9seau). Comme deux adresses sont d\u00e9j\u00e0 prises par le routeur 1 et le routeur 2, il en reste 252.
Le serveur web acc\u00e8de \u00e0 internet via le routeur 2, dont l'adresse sur le r\u00e9seau services est 192.168.254.2
. C'est donc cette adresse qui joue est l'adresse de passerelle pour le serveur web.
Partie 3
Correction Q1.La ligne 2 montre que l'adresse MAC du serveur DNS est 8A:FD:54:49:D0:CC
.
La couche Transport montre que le protocole utilis\u00e9 est le protocole UDP.
Correction Q3.Le commentaire de la couche Application indique que l'adresse IP du serveur web est 192.168.254.201
.
Ce protocole est un exemple simple de fiabilisation du transfert de donn\u00e9es.
"},{"location":"T3_Architecture_materielle/3.4_Protocoles_de_communication/cours/#1-contexte","title":"1. Contexte","text":"Dans cette situation, les sous-messages arrivent tous \u00e0 destination dans le bon ordre. La transmission est correcte.
"},{"location":"T3_Architecture_materielle/3.4_Protocoles_de_communication/cours/#3-situation-reelle","title":"3. Situation r\u00e9elle","text":"Mais parfois, les choses ne se passent pas toujours aussi bien. Car si on ma\u00eetrise parfaitement le timing de l'envoi des sous-messages d'Alice, on ne sait pas combien de temps vont mettre ces sous-messages pour arriver, ni m\u00eame (attention je vais passer dans un tunnel) s'ils ne vont pas \u00eatre d\u00e9truits en route.
Le sous-message M0 est arriv\u00e9 apr\u00e8s le M1, le message M2 n'est jamais arriv\u00e9...
Que faire ?
\u00c9cartons l'id\u00e9e de num\u00e9roter les sous-messages, afin que Bob puisse remettre dans l'ordre les messages arriv\u00e9s, ou m\u00eame redemander sp\u00e9cifiquement des sous-messages perdus. C'est ce que r\u00e9alise le protocole TCP (couche 4 \u2014 transport), c'est tr\u00e8s efficace, mais cher en ressources. Essayons de trouver une solution plus basique.
"},{"location":"T3_Architecture_materielle/3.4_Protocoles_de_communication/cours/#3-solution-naive","title":"3. Solution na\u00efve...","text":"Pourquoi ne pas demander \u00e0 Bob d'envoyer un signal pour dire \u00e0 Alice qu'il vient bien de recevoir son sous-message ? Nous appelerons ce signal ACK (comme acknowledgement, traduisible par \u00abaccus\u00e9 de r\u00e9ception\u00bb). Ce signal ACK permettra \u00e0 Alice de renvoyer un message qu'elle consid\u00e9rera comme perdu :
N'ayant pas re\u00e7u le ACK cons\u00e9cutif \u00e0 son message M1, Alice suppose (avec raison) que ce message n'est pas parvenu jusqu'\u00e0 Bob, et donc renvoie le message M1.
"},{"location":"T3_Architecture_materielle/3.4_Protocoles_de_communication/cours/#4-mais-peu-efficace","title":"4. Mais peu efficace...","text":"Le deuxi\u00e8me ACK de Bob a mis trop de temps pour arriver (ou s'est perdu en route) et donc Alice a suppos\u00e9 que son sous-message M1 n'\u00e9tait pas arriv\u00e9. Elle l'a donc renvoy\u00e9, et Bob se retrouve avec deux fois le sous-message M1. La transmission est incorrecte. En faisant transiter un message entre Bob et Alice, nous multiplions par 2 la probabilit\u00e9 que des probl\u00e8mes techniques de transmission interviennent. Et pour l'instant rien ne nous permet de les d\u00e9tecter.
"},{"location":"T3_Architecture_materielle/3.4_Protocoles_de_communication/cours/#5-bob-prend-le-controle","title":"5. Bob prend le contr\u00f4le","text":"Bob va maintenant int\u00e9grer une m\u00e9thode de validation du sous-message re\u00e7u. Il pourra d\u00e9cider de le garder ou de l'\u00e9carter. Le but est d'\u00e9viter les doublons.
Pour r\u00e9aliser ceci, Alice va rajouter \u00e0 chacun de ses sous-messages un bit de contr\u00f4le, que nous appelerons FLAG (drapeau). Au d\u00e9part, ce FLAG vaut 0. Quand Bob re\u00e7oit un FLAG, il renvoie un ACK \u00e9gal au FLAG re\u00e7u.
Alice va attendre ce ACK contenant le m\u00eame bit que son dernier FLAG envoy\u00e9 :
Bob, de son c\u00f4t\u00e9, va contr\u00f4ler la validit\u00e9 de ce qu'il re\u00e7oit : il ne gardera que les sous-messages dont le FLAG est \u00e9gal \u00e0 l'inverse de son dernier ACK. C'est cette m\u00e9thode qui lui permettra d'\u00e9carter les doublons.
Observons ce protocole dans plusieurs cas :
"},{"location":"T3_Architecture_materielle/3.4_Protocoles_de_communication/cours/#51-cas-ou-le-sous-message-est-perdu","title":"5.1 Cas o\u00f9 le sous-message est perdu","text":""},{"location":"T3_Architecture_materielle/3.4_Protocoles_de_communication/cours/#52-cas-ou-le-ack-est-perdu","title":"5.2 Cas o\u00f9 le ACK est perdu","text":"Le protocole a bien d\u00e9tect\u00e9 le doublon du sous-message M1.
"},{"location":"T3_Architecture_materielle/3.4_Protocoles_de_communication/cours/#53-cas-ou-un-sous-message-est-en-retard","title":"5.3 Cas o\u00f9 un sous-message est en retard","text":"Le protocole a bien d\u00e9tect\u00e9 le doublon du sous-message M1... mais que se passerait-il si notre premier sous-message M1 \u00e9tait encore plus en retard ?
"},{"location":"T3_Architecture_materielle/3.4_Protocoles_de_communication/cours/#6-conclusion","title":"6. Conclusion","text":"Le protocole du bit altern\u00e9 a longtemps \u00e9t\u00e9 utilis\u00e9 au sein de la couche 2 du mod\u00e8le OSI (distribution des trames Ethernet). Simple et l\u00e9ger, il peut toutefois \u00eatre facilement mis en d\u00e9faut, ce qui explique qu'il ait \u00e9t\u00e9 remplac\u00e9 par des protocoles plus performants.
Bibliographie - Num\u00e9rique et Sciences Informatiques, 1re, T. BALABONSKI, S. CONCHON, J.-C. FILLIATRE, K. NGUYEN, \u00e9ditions ELLIPSES. - Pr\u00e9pabac NSI 1\u00e8re, C.ADOBET, G.CONNAN, G. ROZSAVOLGYI, L.SIGNAC, \u00e9ditions Hatier.
"},{"location":"T3_Architecture_materielle/3.5_Decouverte_des_commandes_Linux/cours/","title":"3.5 D\u00e9couverte des commandes UNIX","text":"\u00e0 partir du jeu Terminus
Rendez-vous \u00e0 l'adresse http://luffah.xyz/bidules/Terminus/
Laissez-vous guider par le jeu, mais attention ! - vous devez noter sur un papier chaque nouvelle commande que vous apprenez. Vous pouvez par exemple construire un tableau de ce type :
Activit\u00e9 d'introduction
"},{"location":"T4_Algorithmique/4.1_Extremums_et_moyennes/cours/#1-algorithme-de-recherche-de-maximum","title":"1. Algorithme de recherche de maximum","text":"Recherche de maximum
def recherche_max(tab):\n'''renvoie le maximum de la liste tab'''\n maxi = tab[0] # (1)\n for elt in tab:\n if elt > maxi:\n maxi = elt\n return maxi\n
Utilisation :
>>> recherche_max([4, 3, 8, 1])\n 8\n
"},{"location":"T4_Algorithmique/4.1_Extremums_et_moyennes/cours/#2-algorithme-de-calcul-de-moyenne","title":"2. Algorithme de calcul de moyenne","text":"Calcul de moyenne
def moyenne(tab):\n''' renvoie la moyenne de tab'''\n somme = 0\n for elt in tab:\n somme += elt\n return somme / len(tab)\n
Utilisation :
>>> moyenne([4, 3, 8, 1])\n 4.0\n
"},{"location":"T4_Algorithmique/4.1_Extremums_et_moyennes/cours/#3-algorithme-de-recherche-doccurrence","title":"3. Algorithme de recherche d'occurrence","text":"Recherche d'occurrence
def recherche_occurrence(elt, tab):\n''' renvoie la liste (\u00e9ventuellement vide)\n des indices de elt dans tab'''\n liste_indices = []\n for i in range(len(tab)):\n if tab[i] == elt:\n liste_indices.append(i)\n return liste_indices\n
Utilisation :
>>> recherche_occurrence(3, [1, 6, 3, 8, 3, 2])\n[2, 4]\n>>> recherche_occurrence(7, [1, 6, 3, 8, 3, 2])\n[]\n
"},{"location":"T4_Algorithmique/4.1_Extremums_et_moyennes/intro_cours/","title":"Vers les extremums et moyennes","text":""},{"location":"T4_Algorithmique/4.1_Extremums_et_moyennes/intro_cours/#1-algorithme-de-recherche-de-maximum","title":"1. Algorithme de recherche de maximum","text":"On cherche \u00e0 coder une fonction recherche_max
qui prend en param\u00e8tre une liste tab
et qui renvoie le plus grand \u00e9l\u00e9ment de cette liste. L'usage de la fonction max
est interdit.
Utilisation :
>>> recherche_max([4, 3, 8, 1])\n 8\n
Code \u00e0 trous Recherche de maximum
def recherche_max(tab):\n'''renvoie le maximum de la liste tab'''\n
Code \u00e0 trous Recherche de maximum
def recherche_max(tab):\n'''renvoie le maximum de la liste tab'''\n ... = ... \n for ... in ...:\n if ... > ...:\n ... = ...\n return ...\n
Code \u00e0 trous Recherche de maximum
def recherche_max(tab):\n'''renvoie le maximum de la liste tab'''\n maxi = ... \n for elt in ...:\n if ... > ...:\n ... = ...\n return ...\n
Code \u00e0 trous Recherche de maximum
def recherche_max(tab):\n'''renvoie le maximum de la liste tab'''\n maxi = tab[0] \n for elt in tab:\n if ... > ...:\n maxi = ...\n return ...\n
"},{"location":"T4_Algorithmique/4.1_Extremums_et_moyennes/intro_cours/#2-algorithme-de-calcul-de-moyenne","title":"2. Algorithme de calcul de moyenne","text":"On cherche \u00e0 coder une fonction moyenne
qui prend en param\u00e8tre une liste tab
et qui renvoie la moyenne des \u00e9l\u00e9ments de cette liste.
Utilisation :
>>> moyenne([4, 3, 8, 1])\n 4.0\n
Code \u00e0 trous Recherche de maximum
def moyenne(tab):\n''' renvoie la moyenne de tab'''\n
Code \u00e0 trous Recherche de maximum
def moyenne(tab):\n''' renvoie la moyenne de tab'''\n ... = ...\n for ... in ...:\n ... += ...\n return ... / ...\n
Code \u00e0 trous Recherche de maximum
def moyenne(tab):\n''' renvoie la moyenne de tab'''\n somme = 0\n for elt in ...:\n ... += ...\n return ... / ...\n
Code \u00e0 trous Recherche de maximum
def moyenne(tab):\n''' renvoie la moyenne de tab'''\n somme = 0\n for elt in tab:\n somme += ...\n return ... / ...\n
"},{"location":"T4_Algorithmique/4.1_Extremums_et_moyennes/intro_cours/#3-algorithme-de-recherche-doccurrence","title":"3. Algorithme de recherche d'occurrence","text":"On cherche \u00e0 coder une fonction recherche_occurrence
qui prend en param\u00e8tre un \u00e9lement elt
et une liste tab
et qui renvoie la liste (\u00e9ventuellement vide) des indices de elt
dans tab
.
Utilisation :
>>> recherche_occurrence(3, [1, 6, 3, 8, 3, 2])\n[2, 4]\n>>> recherche_occurrence(7, [1, 6, 3, 8, 3, 2])\n[]\n
Code \u00e0 trous Recherche d'occurrence
def recherche_occurrence(elt, tab):\n''' renvoie la liste (\u00e9ventuellement vide)\n des indices de elt dans tab'''\n
Code \u00e0 trous Recherche d'occurrence
def recherche_occurrence(elt, tab):\n''' renvoie la liste (\u00e9ventuellement vide)\n des indices de elt dans tab'''\n ... = ...\n for ... in range(...):\n if ... == ...:\n ...\n return ...\n
Code \u00e0 trous Recherche d'occurrence
def recherche_occurrence(elt, tab):\n''' renvoie la liste (\u00e9ventuellement vide)\n des indices de elt dans tab'''\n liste_indices = ...\n for i in range(...):\n if ... == ...:\n ....append(i)\n return ...\n
Code \u00e0 trous Recherche d'occurrence
def recherche_occurrence(elt, tab):\n''' renvoie la liste (\u00e9ventuellement vide)\n des indices de elt dans tab'''\n liste_indices = []\n for i in range(len(tab)):\n if tab[i] == ...:\n ....append(i)\n return ...\n
"},{"location":"T4_Algorithmique/4.2_Complexite/cours/","title":"4.2 Complexit\u00e9 d'un algorithme","text":"La complexit\u00e9 d'un algorithme est une notion qui nous \u00e9claire sur la mani\u00e8re dont cet algorithme va \u00eatre sensible \u00e0 la taille des donn\u00e9es pass\u00e9es en param\u00e8tre. Il y a plusieurs types de complexit\u00e9s \u00e9tudiables (nombre d'op\u00e9rations, temps n\u00e9cessaire, espace-m\u00e9moire n\u00e9cessaire...).
En NSI, nous nous contenterons d'estimer (lorsque cela est possible) le nombre d'op\u00e9rations effectu\u00e9es par l'algorithme, et nous mesurerons les temps d'ex\u00e9cution de ces algortihmes.
Nous observerons surtout comment \u00e9volue ce temps d'ex\u00e9cution en fonction de la taille des donn\u00e9es pass\u00e9es en param\u00e8tre (la taille d'une liste, par exemple). Cela nous permettra dans ce cours de classer nos algorithmes en deux cat\u00e9gories : les algorithmes de complexit\u00e9 lin\u00e9aire et ceux de complexit\u00e9 quadratique.
"},{"location":"T4_Algorithmique/4.2_Complexite/cours/#1-complexite-lineaire","title":"1. Complexit\u00e9 lin\u00e9aire","text":""},{"location":"T4_Algorithmique/4.2_Complexite/cours/#11-exemple","title":"1.1 Exemple","text":"Exemple d'algorithme
Votre travail est de mettre des bulletins dans des enveloppes pour une campagne de communication. L'algorithme en jeu ici est \"je prends un bulletin, je le plie, je le mets dans l'enveloppe, je ferme l'enveloppe\".
On suppose que vous travaillez \u00e0 un rythme constant. Le premier jour, on vous donne \\(n\\) enveloppes \u00e0 remplir. Vous mettez un temps \\(T\\) pour les traiter. Le deuxi\u00e8me jour, suite \u00e0 l'absence d'un employ\u00e9, on vous donne le double d'enveloppes, soit \\(2n\\) enveloppes. Combien de temps allez vous mettre pour les traiter ?
R\u00e9ponseCela prendra deux fois plus de temps, donc \\(2T\\).
"},{"location":"T4_Algorithmique/4.2_Complexite/cours/#12-vocabulaire","title":"1.2 Vocabulaire","text":"On dit que l'algorithme ci-dessus est de complexit\u00e9 lin\u00e9aire.
Complexit\u00e9 lin\u00e9aire
Les expressions suivantes sont \u00e9quivalentes :
Toutes ces formulations renvoient \u00e0 la m\u00eame id\u00e9e : le nombre d'op\u00e9rations n\u00e9cessaires (et donc le temps n\u00e9cessaire \u00e0 la terminaison de l'algorithme) \u00e9volue proportionnellement avec le nombre de donn\u00e9es \u00e0 traiter.
"},{"location":"T4_Algorithmique/4.2_Complexite/cours/#13-formulation-mathematique","title":"1.3 Formulation math\u00e9matique","text":"Si un employ\u00e9 A met 3 secondes par enveloppe, on aura \\(T_A=3n\\). Si un employ\u00e9 B met 20 secondes par enveloppe, on aura \\(T_B=20n\\).
On retrouve la formulation math\u00e9matique d'une fonction lin\u00e9aire \\(f\\).
\\[f : x \\mapsto ax \\quad\\text{ , avec } a \\in \\mathbb{R}\\]Ici, la fonction \\(f_A\\) serait \\(f_A(x)=3x\\), la fonction \\(f_B\\) serait \\(f_B(x)=20x\\)
Dans les deux cas l'algorithme a la m\u00eame complexit\u00e9 (lin\u00e9aire donc). Ce qui compte est le fait que pour chacun des employ\u00e9s, avoir deux fois plus d'enveloppes prendrait deux fois plus de temps.
"},{"location":"T4_Algorithmique/4.2_Complexite/cours/#14-verification-experimentale","title":"1.4 V\u00e9rification exp\u00e9rimentale","text":"On consid\u00e8re la fonction ci-dessous :
def fabrique(n):\n liste = []\n for _ in range(n):\n liste.append(\"ok\")\n return liste\n
Le code ci-dessous va mesurer le temps d'ex\u00e9cution de cette fonction avec deux param\u00e8tres diff\u00e9rents : la valeur 400 puis la valeur 800.
import time\nt0 = time.time()\nlstA = fabrique(400)\nprint(\"temps pour une liste de taille 400 :\", time.time() - t0)\nt0 = time.time()\nlstB = fabrique(800)\nprint(\"temps pour une liste de taille 800 :\", time.time() - t0)\n
R\u00e9sultats de l'ex\u00e9cution :
temps pour une liste de taille 400 : 2.384185791015625e-05\ntemps pour une liste de taille 800 : 4.2438507080078125e-05\n
Interpr\u00e9tation : Doubler la taille du param\u00e8tre d'entr\u00e9e a eu pour effet de doubler (quasiment) le temps d'ex\u00e9cution. Cela semble indiquer que la complexit\u00e9 de cette fonction est lin\u00e9aire. En observant l'algorithme, nous pouvons confirmer cette supposition : le nombre d'op\u00e9rations de la boucle for
est \u00e9gal au param\u00e8tre n
, et est donc directement proportionnel \u00e0 la valeur de ce param\u00e8tre.
Exemple d'algorithme
Vous avez l'habitude de tondre la pelouse de votre terrain carr\u00e9, de c\u00f4t\u00e9 \\(n\\). Cela vous prend un certain temps \\(T\\). Votre voisin vous propose de venir chez lui tondre son terrain carr\u00e9 de c\u00f4t\u00e9 \\(2n\\). Combien de temps cela va-t-il vous prendre pour tondre le terrain de votre voisin ?
R\u00e9ponseCela vous prendra 4 fois plus de temps.
"},{"location":"T4_Algorithmique/4.2_Complexite/cours/#22-vocabulaire","title":"2.2 Vocabulaire","text":"On dit que l'algorithme ci-dessus est de complexit\u00e9 quadratique.
Complexit\u00e9 quadratique
Les expressions suivantes sont \u00e9quivalentes :
Toutes ces formulations renvoient \u00e0 la m\u00eame id\u00e9e : le nombre d'op\u00e9rations n\u00e9cessaires (et donc le temps n\u00e9cessaire \u00e0 la terminaison de l'algorithme) \u00e9volue proportionnellement avec le carr\u00e9 du nombre de donn\u00e9es \u00e0 traiter.
Les algorithmes quadratiques sont moins \u00abint\u00e9ressants\u00bb que les algorithmes lin\u00e9aires, car ils vont consommer beaucoup plus de ressources. Lors de l'\u00e9laboration d'un algorithme, on va toujours essayer de trouver l'algorithme ayant la complexit\u00e9 la plus faible possible.
"},{"location":"T4_Algorithmique/4.2_Complexite/cours/#23-verification-experimentale","title":"2.3 V\u00e9rification exp\u00e9rimentale","text":"On consid\u00e8re la fonction ci-dessous :
def tables(n):\n for a in range(n):\n for b in range(n):\n c = a * b\n
Le code ci-dessous va mesurer le temps d'ex\u00e9cution de cette fonction avec deux param\u00e8tres diff\u00e9rents : la valeur 100 puis la valeur 200.
import time\nt0 = time.time()\ntables(100)\nprint(\"temps pour n = 100 :\", time.time() - t0)\nt0 = time.time()\ntables(200)\nprint(\"temps pour n = 200 : \", time.time() - t0)\n
R\u00e9sultats de l'ex\u00e9cution :
temps pour n = 100 : 0.0003533363342285156\ntemps pour n = 200 : 0.0014693737030029297\n
Interpr\u00e9tation : Doubler la taille du param\u00e8tre d'entr\u00e9e a eu pour effet de quadrupler le temps d'ex\u00e9cution. Cela semble indiquer que la complexit\u00e9 de cette fonction est quadratique, car \\(2^2=4\\).
En observant l'algorithme, nous pouvons confirmer cette supposition : le nombre d'op\u00e9rations des deux boucles for
est \u00e9gal \u00e0 n^2
.
Il peut arriver (mais c'est rare) que la complexit\u00e9 d'un algorithme soit ind\u00e9pendante de la taille des donn\u00e9es \u00e0 traiter. Dans ce cas, c'est souvent une tr\u00e8s bonne nouvelle.
Observons l'acc\u00e8s au 1er \u00e9l\u00e9ment d'une liste :
Complexit\u00e9 constante
Les expressions suivantes sont \u00e9quivalentes :
Toutes ces formulations renvoient \u00e0 la m\u00eame id\u00e9e : le nombre d'op\u00e9rations n\u00e9cessaires (et donc le temps n\u00e9cessaire \u00e0 la terminaison de l'algorithme) est constant quelle que soit la taille des donn\u00e9es d'entr\u00e9e de l'algorithme.
"},{"location":"T4_Algorithmique/4.3_Tri_par_insertion/cours/","title":"4.3 Tri par insertion","text":""},{"location":"T4_Algorithmique/4.3_Tri_par_insertion/cours/#0-introduction","title":"0. Introduction","text":"Activit\u00e9 d'introduction
"},{"location":"T4_Algorithmique/4.3_Tri_par_insertion/cours/#1-tri-par-insertion-version-la-plus-intuitive","title":"1. Tri par insertion (version la plus intuitive)","text":""},{"location":"T4_Algorithmique/4.3_Tri_par_insertion/cours/#11-principe-et-algorithme","title":"1.1 Principe et algorithme","text":"Consid\u00e9rons la liste [7, 5, 2, 8, 1, 4]
Voici le fonctionnement de l'algorithme :
Explications :
Algorithme :
Pour toutes les valeurs, en commen\u00e7ant par la deuxi\u00e8me :
Tri par insertion (version simple)
def tri_insertion(lst):\n'''trie en place la liste lst donn\u00e9e en param\u00e8tre'''\n for i in range(1, len(lst)): #(1)\n k = i #(2)\n while k > 0 and lst[k-1] > lst[k] : #(3)\n lst[k], lst[k-1] = lst[k-1], lst[k] #(4) \n k = k - 1 #(5) \n
i
en une variable k
. On se positionne sur l'\u00e9l\u00e9ment d'indice k
. On va faire \u00abreculer\u00bb cet \u00e9l\u00e9ment tant que c'est possible. On ne touche pas \u00e0 i
. k - 1
. La boucle peut continuer.Application :
>>> maliste = [7, 5, 2, 8, 1, 4]\n>>> tri_insertion(maliste)\n>>> maliste\n[1, 2, 4, 5, 7, 8]\n
"},{"location":"T4_Algorithmique/4.3_Tri_par_insertion/cours/#2-tri-par-insertion-version-optimisee","title":"2. Tri par insertion (version optimis\u00e9e)","text":""},{"location":"T4_Algorithmique/4.3_Tri_par_insertion/cours/#21-principe-et-algorithme","title":"2.1 Principe et algorithme","text":"Observez l'animation ci-dessous et comparer avec la version initiale.
Tri par insertion (version optimis\u00e9e)
def tri_insertion_v2(lst) :\n'''trie en place la liste lst donn\u00e9e en param\u00e8tre'''\n for i in range(1, len(lst)): # (1)\n cle = lst[i] # (2)\n k = i - 1 # (3)\n while k >= 0 and lst[k] > cle : # (4)\n lst[k + 1] = lst[k] # (5)\n k = k -1 # (6)\n lst[k + 1] = cle # (7)\n
cle
notre valeur de travailApplication :
>>> maliste = [7, 5, 2, 8, 1, 4]\n>>> tri_insertion_v2(maliste)\n>>> maliste\n[1, 2, 4, 5, 7, 8]\n
"},{"location":"T4_Algorithmique/4.3_Tri_par_insertion/cours/#3-complexite-de-lalgorithme","title":"3. Complexit\u00e9 de l'algorithme","text":""},{"location":"T4_Algorithmique/4.3_Tri_par_insertion/cours/#31-etude-experimentale","title":"3.1 \u00c9tude exp\u00e9rimentale","text":"Lire le cours sur la complexit\u00e9 et proposer des mesures exp\u00e9rimentales pour d\u00e9terminer la complexit\u00e9 du tri par insertion.
"},{"location":"T4_Algorithmique/4.3_Tri_par_insertion/cours/#32-demonstration","title":"3.2 D\u00e9monstration","text":"D\u00e9nombrons le nombre d'op\u00e9rations dans le pire des cas, pour une liste de taille \\(n\\).
for
: elle s'ex\u00e9cute \\(n-1\\) fois.while
: dans le pire des cas, elle ex\u00e9cute d'abord 1 op\u00e9ration, puis 2, puis 3... jusqu'\u00e0 \\(n-1\\). Or Le terme de plus haut degr\u00e9 de l'expression \\(\\dfrac{n \\times (n-1)}{2}\\) est de degr\u00e9 2 : le nombre d'op\u00e9rations effectu\u00e9es est donc proportionnel au carr\u00e9 de la taille des donn\u00e9es d'entr\u00e9e. Ceci d\u00e9montre que le tri par insertion est de complexit\u00e9 quadratique.
Dans le cas (rare, mais il faut l'envisager) o\u00f9 la liste est d\u00e9j\u00e0 tri\u00e9e, on ne rentre jamais dans la boucle while
: le nombre d'op\u00e9rations est dans ce cas \u00e9gal \u00e0 \\(n-1\\), ce qui caract\u00e9rise une complexit\u00e9 lin\u00e9aire.
Est-on s\u00fbr que notre algorithme va s'arr\u00eater ? Le programme est constitu\u00e9 d'une boucle while
imbriqu\u00e9e dans une boucle for
. Seule la boucle while
peut provoquer une non-terminaison de l'algorithme. Observons donc ses conditions de sortie :
while k >= 0 and l[k] > cle :\n
La condition l[k] > cle
ne peut pas \u00eatre rendue fausse avec certitude. Par contre, la condition k >= 0
sera fausse d\u00e8s que la variable k
deviendra n\u00e9gative. Or la ligne k = k - 1
nous assure que la variable k
diminuera \u00e0 chaque tour de boucle. La condition k >= 0
deviendra alors forc\u00e9ment fausse au bout d'un certain temps.
Nous avonc donc prouv\u00e9 la terminaison de l'algorithme.
Vocabulaire
On dit que la valeur k
est un variant de boucle. C'est une notion th\u00e9orique (ici illustr\u00e9e de mani\u00e8re simple par la valeur k
) qui permet de prouver la bonne sortie d'une boucle et donc la terminaison d'un algorithme.
Les preuves de correction sont des preuves th\u00e9oriques. La preuve ici s'appuie sur le concept math\u00e9matique de r\u00e9currence. Principe du raisonnement par r\u00e9currence : une propri\u00e9t\u00e9 \\(P(n)\\) est vraie si :
Ici, la propri\u00e9t\u00e9 serait : \u00ab Quand \\(k\\) varie entre 0 et longueur(liste) -1
, la sous-liste de longueur \\(k\\) est tri\u00e9e dans l'ordre croissant.\u00bb
Vocabulaire
On appelle cette propri\u00e9t\u00e9 un invariant de boucle. Invariant siginifie qu'elle reste vraie pour chaque boucle.
def tri_insertion(lst):\n'''trie en place la liste lst donn\u00e9e en param\u00e8tre'''\n
Code \u00e0 trous def tri_insertion(lst):\n'''trie en place la liste lst donn\u00e9e en param\u00e8tre'''\n for i in range(..., ...): \n ... = ... \n while ... > ... and ... > ... : \n ..., ... = ..., ... \n ... = ... \n
Code \u00e0 trous def tri_insertion(lst):\n'''trie en place la liste lst donn\u00e9e en param\u00e8tre'''\n for i in range(..., len(lst)): \n k = ... \n while k > ... and lst[...] > lst[...] : \n lst[...], lst[...] = lst[...], lst[...] \n k = ... \n
Code \u00e0 trous def tri_insertion(lst):\n'''trie en place la liste lst donn\u00e9e en param\u00e8tre'''\n for i in range(1, len(lst)): \n k = ... \n while k > ... and lst[k-1] > lst[k] : \n lst[k], lst[k-1] = lst[...], lst[...] \n k = ... \n
"},{"location":"T4_Algorithmique/4.4_Tri_par_selection/cours/","title":"4.4 Tri par s\u00e9lection","text":""},{"location":"T4_Algorithmique/4.4_Tri_par_selection/cours/#0-preambule","title":"0. Pr\u00e9ambule","text":"Pourquoi \u00e9tudier des algorithmes de tri ? Autant ne pas le cacher, ces algorithmes sont d\u00e9j\u00e0 impl\u00e9ment\u00e9s (quelque soit le langage) dans des fonctions tr\u00e8s performantes.
En Python, on utilise la fonction sort()
:
>>> tab = [4, 8, 1, 2, 6]\n>>> tab.sort()\n>>> tab\n[1, 2, 4, 6, 8]\n
Le meilleur de nos futurs algorithmes de tri sera moins efficace que celui de cette fonction sort()
... Malgr\u00e9 cela, il est essentiel de se confronter \u00e0 l'\u00e9laboration manuelle d'un algorithme de tri. Le tri par s\u00e9lection est le premier des deux algorithmes de tri que nous allons \u00e9tudier (nous \u00e9tudierons aussi le tri par insertion). Ces deux algorithmes ont pour particularit\u00e9 de :
Activit\u00e9 d'introduction
"},{"location":"T4_Algorithmique/4.4_Tri_par_selection/cours/#1-animation","title":"1. Animation","text":"Consid\u00e9rons la liste [5, 4, 2, 1]
Voici le fonctionnement de l'algorithme :
"},{"location":"T4_Algorithmique/4.4_Tri_par_selection/cours/#2-principe","title":"2. Principe","text":"
Comme dans tous les autres algorithmes de tri que nous allons \u00e9tudier, nous allons travailler en place. Cela signifie que nous ne travaillons que sur la liste initiale, sans en cr\u00e9er de nouvelles. Le tri sera fait en permutant des \u00e9l\u00e9ments.
Tr\u00e8s tr\u00e8s grossi\u00e8rement, l'id\u00e9e de l'algorithme est la suivante :
Pour r\u00e9aliser ceci, le travail va se faire en manipulant les indices des \u00e9l\u00e9ments de la liste.
Description de l'algorithme
Le travail se fait essentiellement sur les indices.
Tri par s\u00e9lection
def tri_selection(lst) :\n for i in range(len(lst)-1):\n indice_min = i\n for k in range(i+1, len(lst)) :\n if lst[k] < lst[indice_min]:\n indice_min = k\n lst[i], lst[indice_min] = lst[indice_min], lst[i]\n
V\u00e9rification :
>>> ma_liste = [7, 5, 2, 8, 1, 4]\n>>> tri_selection(ma_liste)\n>>> ma_liste\n[1, 2, 4, 5, 7, 8]\n
"},{"location":"T4_Algorithmique/4.4_Tri_par_selection/cours/#4-complexite-de-lalgorithme","title":"4. Complexit\u00e9 de l'algorithme","text":""},{"location":"T4_Algorithmique/4.4_Tri_par_selection/cours/#40-de-quoi-parle-t-on","title":"4.0. De quoi parle-t-on ?","text":"Cours sur la complexit\u00e9
"},{"location":"T4_Algorithmique/4.4_Tri_par_selection/cours/#41-calcul-du-nombre-doperations","title":"4.1. Calcul du nombre d'op\u00e9rations","text":"La ligne 3 indice_min = i
va s'ex\u00e9cuter \\(n\\) fois. Mais int\u00e9ressons-nous \u00e0 la ligne 5 (le test) : combien de fois va-t-elle s'ex\u00e9cuter ? \u00c0 chaque tour de la premi\u00e8re boucle (qui en comporte \\(n\\)), le nombre d'op\u00e9rations de la 2\u00e8me boucle va varier :
Or \\(1+2+3+\\dots+n-1=\\dfrac{n \\times (n-1)}{2}= \\dfrac{1}{2}n^2 - \\dfrac{1}{2}n\\)
Dans cette expression, un terme joue un r\u00f4le fondamental : \\(n^2\\). C'est le terme pr\u00e9pond\u00e9rant (le terme de plus haut degr\u00e9), qui va \u00e0 lui seul caract\u00e9riser la mani\u00e8re dont le nombre d'op\u00e9rations \u00e9volue en fonction de \\(n\\).
Ici, \\(n\\) est \u00e9lev\u00e9 au carr\u00e9, ce qui signifie que le nombre d'op\u00e9rations va \u00e9voluer avec le carr\u00e9 du nombre de termes de la liste \u00e0 trier.
Complexit\u00e9 du tri par s\u00e9lection
Le tri par s\u00e9lection a une complexit\u00e9 quadratique.
"},{"location":"T4_Algorithmique/4.4_Tri_par_selection/cours/#42-influence-de-la-taille-de-la-liste-sur-le-temps-dexecution","title":"4.2 Influence de la taille de la liste sur le temps d'ex\u00e9cution","text":"Consid\u00e9rons qu'une liste de taille \\(n\\) est tri\u00e9e par l'algorithme de tri par s\u00e9lection en un temps \\(T\\). Le temps d'ex\u00e9cution d\u00e9pendant du nombre d'op\u00e9rations \u00e0 traiter, il va \u00e9voluer avec le carr\u00e9 de la taille de la liste.
Voici donc un ordre de grandeur de ce que devraient \u00eatre les temps n\u00e9cessaires pour trier une liste de taille \\(2n\\) ou \\(10n\\).
Taille de la liste Temps \\(n\\) \\(T\\) \\(2n\\) \\(4T\\) \\(10n\\) \\(100T\\)"},{"location":"T4_Algorithmique/4.4_Tri_par_selection/cours/#43-verification-experimentale","title":"4.3 V\u00e9rification exp\u00e9rimentale","text":"Exercice
\u00c9nonc\u00e9CorrectionAnalyser le code suivant :
import time\n\ndef tri_selection(lst):\n for i in range(len(lst)-1):\n i_min = i\n for k in range(i, len(lst)):\n if lst[k] < lst[i_min]:\n i_min = k\n lst[i_min], lst[i] = lst[i], lst[i_min]\n\n\ndef mesures(n):\n total_temps = 0\n for _ in range(5):\n lst = list(range(n, 0, -1)) # (1)\n t0 = time.time()\n tri_selection(lst)\n delta_t = time.time() - t0\n total_temps += delta_t\n tps_moy = total_temps / 5\n print(f\"temps moyen pour trier une liste de taille {n} : {tps_moy}\")\n
Q1. Essayer de confirmer les r\u00e9sultats th\u00e9oriques du tableau pr\u00e9c\u00e9dent. On pourra travailler par exemple avec une liste initiale de taille 1000.
Q2. Recommencer avec une liste d\u00e9j\u00e0 tri\u00e9e. Que constate-t-on ?
Q1.
>>> mesures(10**3)\ntemps moyen pour trier une liste de taille 1000 : 0.03579235076904297\n>>> mesures(2*10**3)\ntemps moyen pour trier une liste de taille 2000 : 0.13821134567260743\n>>> mesures(10**4)\ntemps moyen pour trier une liste de taille 10000 : 3.3528685569763184\n
On retrouve (\u00e0 peu pr\u00e8s, mais plut\u00f4t bien) le facteur 4 quand la taille de la liste double, et le facteur 100 quand la taille de la liste est multipli\u00e9e par 10.
Q2. Changeons la ligne lst = list(range(n, 0, -1))
en lst = list(range(n))
:
>>> mesures(10**3)\ntemps moyen pour trier une liste de taille 1000 : 0.038380765914916994\n>>> mesures(2*10**3)\ntemps moyen pour trier une liste de taille 2000 : 0.13413033485412598\n>>> mesures(10**4)\ntemps moyen pour trier une liste de taille 10000 : 3.213682508468628\n
Les mesures sont identiques : l'\u00e9tat initial de la liste n'a pas d'influence.
"},{"location":"T4_Algorithmique/4.4_Tri_par_selection/cours/#5-preuve-de-la-terminaison-de-lalgorithme","title":"5.\u00a0Preuve de la terminaison de l'algorithme","text":"Est-on s\u00fbr que notre algorithme va s'arr\u00eater ?
\u00c0 l'observation du programme, constitu\u00e9 de deux boucles for
imbriqu\u00e9es, il n'y a pas d'ambigu\u00eft\u00e9 : on ne peut pas rentrer dans une boucle infinie. Le programme s'arr\u00eate forc\u00e9ment au bout de d'un nombre fixe d'op\u00e9rations. D'apr\u00e8s nos calculs sur la complexit\u00e9, ce nombre de tours de boucles est \u00e9gal \u00e0 \\(\\dfrac{n \\times (n-1)}{2}\\).
Ceci prouve que l'algorithme se terminera.
"},{"location":"T4_Algorithmique/4.4_Tri_par_selection/cours/#6-preuve-de-la-correction-de-lalgorithme","title":"6. Preuve de la correction de l'algorithme","text":"Est-on s\u00fbr que notre algorithme va bien trier notre liste ?
Les preuves de correction sont des preuves th\u00e9oriques. La preuve ici s'appuie sur le concept math\u00e9matique de r\u00e9currence. Principe du raisonnement par r\u00e9currence : une propri\u00e9t\u00e9 \\(P(n)\\) est vraie si :
Ici, la propri\u00e9t\u00e9 serait : \u00ab Quand \\(k\\) varie entre 0 et longueur(liste) -1
, la sous-liste de longueur \\(k\\) est tri\u00e9e dans l'ordre croissant.\u00bb On appelle cette propri\u00e9t\u00e9 un invariant de boucle (sous-entendu : elle est vraie pour chaque boucle)
Une jolie animation permettant de comparer les tris : (on peut y constater que le tri par s\u00e9lection met toujours autant de temps pour trier la liste, quelque soit son \u00e9tat initial)
Issue de ce site.
"},{"location":"T4_Algorithmique/4.4_Tri_par_selection/intro_cours/","title":"Vers le tri par s\u00e9lection","text":"Code \u00e0 trousdef tri_selection(lst) :\n ...\n
Code \u00e0 trous def tri_selection(lst) :\n for ... in ... :\n ... = ...\n for ... in ... :\n if ... :\n ...\n ...\n
Code \u00e0 trous def tri_selection(lst) :\n for i in range(...):\n ... = i\n for k in range(..., ...) :\n if ... < ... :\n ... = ...\n ..., ... = ..., ...\n
Code \u00e0 trous def tri_selection(lst) :\n for i in range(len(lst)-1):\n indice_min = ...\n for k in range(..., len(lst)) :\n if lst[...] < lst[...]:\n indice_min = ...\n lst[...], lst[...] = lst[...], lst[...]\n
"},{"location":"T4_Algorithmique/4.5_Dichotomie/cours/","title":"4.5 Dichotomie","text":"ou comment rechercher efficacement dans une liste tri\u00e9e ?
\u00abdichotomie\u00bb se dit en anglais binary search.
"},{"location":"T4_Algorithmique/4.5_Dichotomie/cours/#1-introduction-recherche-dune-valeur-dans-une-liste","title":"1. Introduction : recherche d'une valeur dans une liste","text":""},{"location":"T4_Algorithmique/4.5_Dichotomie/cours/#11-preambule","title":"1.1 Pr\u00e9ambule","text":"De l'importance de bien ranger ses affaires
Les premiers algorithmes \u00abc\u00e9l\u00e8bres\u00bb que nous avons d\u00e9couverts \u00e9taient des algorithmes de tri.
Quel est l'int\u00e9r\u00eat de trier ses donn\u00e9es ?
l'int\u00e9r\u00eat imm\u00e9diat est d'en tirer un classement : quelle est la plus grande (ou plus petite) valeur, la deuxi\u00e8me, la troisi\u00e8me... On s'en sert donc \u00e9videmment pour d\u00e9terminer une valeur optimale, un gagnant dans une comp\u00e9tition, etc. Mais il y a une autre raison plus importante.
Trier ses donn\u00e9es permet de rechercher plus rapidement une valeur pr\u00e9cise parmi celles-ci.
Exemple : pouvez-vous deviner la couleur \u00e0 laquelle je pense ?
coul = [\"bleu\", \"jaune\", \"rouge\", \"vert\", \"violet\", \"marron\"]\n
Toutes les m\u00e9thodes (proposition des valeurs dans l'ordre, au hasard, dans l'ordre inverse...) sont \u00e9quivalentes : elles sont toutes aussi mauvaises, aucune strat\u00e9gie n'est possible car les donn\u00e9es ne sont pas tri\u00e9es. Si je suis \u00e0 la recherche de la valeur \"vert\", le fait de piocher \"rouge\" ne me donnera aucune indication sur le fait que je devrais chercher plus \u00e0 gauche \u00e0 plus \u00e0 droite que l'endroit o\u00f9 j'ai pioch\u00e9.
Il faudrait pour cela que la liste soit tri\u00e9e (et donc qu'elle soit \u00abtriable\u00bb, ce qui n'est pas toujours le cas !). C'est donc le cas dans lequel nous allons nous placer dans toute la suite de ce cours :
Dans toute la suite, nous rechercherons un \u00e9l\u00e9ment dans une liste d'entiers tri\u00e9e dans l'ordre croissant.
"},{"location":"T4_Algorithmique/4.5_Dichotomie/cours/#12-contexte-de-recherche","title":"1.2 Contexte de recherche","text":"Consid\u00e9rons donc la liste lst
suivante :
lst = [2, 3, 6, 7, 11, 14, 18, 19, 24]\n
L'objectif est de d\u00e9finir un algorithme de recherche efficace d'une valeur arbitraire pr\u00e9sente dans cette liste.
"},{"location":"T4_Algorithmique/4.5_Dichotomie/cours/#13-methode-naive-recherche-par-balayage","title":"1.3 M\u00e9thode na\u00efve : recherche par balayage","text":"C'est la m\u00e9thode la plus intuitive : on essaie toutes les valeurs (par exemple, dans l'ordre croissant) jusqu'\u00e0 trouver la bonne.
Exercice 1
\u00c9nonc\u00e9Correction\u00c9crire un code permettant d'afficher l'indice de la valeur 14
dans la liste lst = [2, 3, 6, 7, 11, 14, 18, 19, 24]
.
lst = [2, 3, 6, 7, 11, 14, 18, 19, 24]\nfor k in range(len(lst)):\n if lst[k] == 14 :\n print(k)\n
Exercice 2
\u00c9nonc\u00e9Correction\u00c9crire une fonction trouve
qui re\u00e7oit pour param\u00e8tres une liste lst
et un nombre val
et qui renvoie l'indice de val
dans la liste lst
. Si la valeur val
n'est pas trouv\u00e9e, on renverra \"non trouv\u00e9\"
.
def trouve(val, lst) :\n for k in range(len(lst)) :\n if lst[k] == val:\n return k\n return \"non trouv\u00e9\"\n
"},{"location":"T4_Algorithmique/4.5_Dichotomie/cours/#13-complexite-de-la-methode-naive","title":"1.3 Complexit\u00e9 de la m\u00e9thode na\u00efve","text":"Complexit\u00e9 de la m\u00e9thode na\u00efve
Dans le cas d'une recherche na\u00efve, le nombre (maximal) d'op\u00e9rations n\u00e9cessaires est proportionnel \u00e0 la taille de la liste \u00e0 \u00e9tudier. Si on appelle \\(n\\) la longueur de la liste, on dit que cet algorithme est d'ordre \\(n\\), ou lin\u00e9aire, ou en \\(O(n)\\).
Remarque : La m\u00e9thode na\u00efve n'utilise pas le fait que la liste est tri\u00e9e, on aurait pu aussi bien l'utiliser sur une liste non tri\u00e9e.
"},{"location":"T4_Algorithmique/4.5_Dichotomie/cours/#2-recherche-dichotomique","title":"2. Recherche dichotomique","text":""},{"location":"T4_Algorithmique/4.5_Dichotomie/cours/#21-introduction-le-jeu-du-devine-un-nombre-entre-1-et-100","title":"2.1 Introduction : le jeu du \u00abdevine un nombre entre 1 et 100\u00bb","text":"R\u00e8gles du jeu
Si je choisis un nombre entre 1 et 100, quelle est la strat\u00e9gie optimale pour deviner ce nombre le plus vite possible ? (\u00e0 chaque \u00e9tape, une indication (trop grand, trop petit) permet d'affiner la proposition suivante)
R\u00e9ponse attendue : la meilleure strat\u00e9gie est de couper en deux \u00e0 chaque fois l'intervalle d'\u00e9tude. On d\u00e9marre de 50, puis 75 ou 25, etc.
Il convient toute fois de remettre en question cette m\u00e9thode qui para\u00eet naturellement optimale : si je propose 90 comme nombre de d\u00e9part, j'ai certes moins de chance que le nombre soit entre 90 et 100, mais s'il l'est, j'ai gagn\u00e9 un gros avantage car mon nouvel intervalle est tr\u00e8s r\u00e9duit.
Notion d'esp\u00e9rance probabilisteD\u00e9terminer si un risque vaut la peine d'\u00eatre pris passe par la compr\u00e9hension de la notion d'esp\u00e9rance probabiliste. Exemple : \"On lance un d\u00e9, s'il tombe sur le 6 vous recevez 8 euros, sinon vous me donnez 1 euro. Voulez-vous jouer ?\"
\\(E(X) = 8 \\times \\frac{1}{6} + (-1) \\times \\frac{5}{6} = \\frac{8}{6}-\\frac{5}{6}=\\frac12\\)
En moyenne, on gagnera 50 centimes par partie, il faut donc jouer.
Le graphique ci-dessous repr\u00e9sente le nombre de coups moyens (sur 10 000 parties simul\u00e9es)
Interpr\u00e9tations et remarques
La strat\u00e9gie optimale est de diviser en deux \u00e0 chaque \u00e9tape l'intervalle d'\u00e9tude. On appelle cela une m\u00e9thode par dichotomie, du grec ancien \u03b4\u03b9\u03c7\u03bf\u03c4\u03bf\u03bc\u03af\u03b1, dikhotomia (\u00ab division en deux parties \u00bb).
"},{"location":"T4_Algorithmique/4.5_Dichotomie/cours/#22-algorithme-de-recherche-dichotomique","title":"2.2 Algorithme de recherche dichotomique","text":"Dichotomie, d\u00e9roulement intuitif
Comprendre la m\u00e9thode de dichotomie est relativement simple, mais savoir la programmer est plus difficile.
Pour des raisons d'efficacit\u00e9, nous allons garder intacte notre liste de travail et simplement faire \u00e9voluer les indices qui d\u00e9terminent le d\u00e9but et la fin de notre liste.
Une autre m\u00e9thode pourrait \u00eatre d'extraire \u00e0 chaque \u00e9tape une nouvelle liste (dont on esp\u00e8re qu'elle contient la valeur cherch\u00e9e), mais la technique utilis\u00e9e (le slicing de liste) consomme beaucoup trop de ressources.
Nous allons donc travailler avec trois variables :
indice_debut
(en bleu sur le sch\u00e9ma)indice_fin
(en bleu sur le sch\u00e9ma)indice_central
, qui est \u00e9gale \u00e0 (indice_debut + indice_fin) // 2
(en rouge sur le sch\u00e9ma) Nous allons faire se rapprocher les indices indice_debut
et indice_fin
tant que indice_debut <= indice_fin
Codes \u00e0 trous
Recherche dichotomique dans une liste tri\u00e9e
def recherche_dichotomique(lst, val) :\n indice_debut = 0\n indice_fin = len(lst) - 1\n while indice_debut <= indice_fin :\n indice_centre = (indice_debut + indice_fin) // 2 \n valeur_centrale = lst[indice_centre] \n if valeur_centrale == val : \n return indice_centre\n if valeur_centrale < val : \n indice_debut = indice_centre + 1\n else :\n indice_fin = indice_centre - 1\n return None\n
Utilisation
>>> mylist = [2, 3, 6, 7, 11, 14, 18, 19, 24]\n>>> recherche_dichotomique(mylist, 14)\n5\n>>> recherche_dichotomique(mylist, 2)\n0\n>>> recherche_dichotomique(mylist, 24)\n8\n>>> recherche_dichotomique(mylist, 2022)\n>>> \n
"},{"location":"T4_Algorithmique/4.5_Dichotomie/cours/#24-visualisations-avec-pythontutor","title":"2.4 Visualisations avec PythonTutor","text":"Cas o\u00f9 la valeur est trouv\u00e9e
Cas o\u00f9 la valeur N'est PAS trouv\u00e9e
"},{"location":"T4_Algorithmique/4.5_Dichotomie/cours/#25-terminaison-de-lalgorithme","title":"2.5 Terminaison de l'algorithme","text":"
Est-on s\u00fbr que l'algorithme va se terminer ? La boucle while
qui est utilis\u00e9e doit nous inciter \u00e0 la prudence (voir cours sur la boucle While). Il y a en effet le risque de rentrer dans une boucle infinie. Pourquoi n'est-ce pas le cas ?
Aide : observer la position des deux fl\u00e8ches bleues lors de l'ex\u00e9cution de l'algorithme
La condition de la boucle while
est indice_debut <= indice_fin
, qui pourrait aussi s'\u00e9crire indice_fin >= indice_debut
. Au d\u00e9marrage de la boucle, on a :
indice_debut = 0\n indice_fin = len(L) - 1\n
Ceci qui nous assure donc de bien rentrer dans la boucle.
Ensuite, \u00e0 chaque \u00e9tape :
indice_debut
augmente strictement (gr\u00e2ce \u00e0 indice_debut = indice_centre + 1
)indice_fin
diminue strictement (gr\u00e2ce \u00e0 indice_fin = indice_centre - 1
)Il va donc forc\u00e9ment arriver un moment o\u00f9 indice_fin
sera inf\u00e9rieur \u00e0 indice_debut
: on sortira alors de la boucle et le programme va bien se terminer.
Variant de boucle On dit que la valeur indice_fin - indice_debut
repr\u00e9sente le variant de boucle de cet algorithme. Ce variant est un nombre entier, d'abord strictement positif, puis qui va d\u00e9cro\u00eetre jusqu'\u00e0 la valeur 0.
Combien d'\u00e9tapes (au maximum) sont-elles n\u00e9cessaires pour arriver \u00e0 la fin de l'algorithme ? Imaginons que la liste initiale poss\u00e8de 8 valeurs. Apr\u00e8s une \u00e9tape, il ne reste que 4 valeurs \u00e0 traiter. Puis 2 valeurs. Puis une seule valeur. Il y a donc 3 \u00e9tapes avant de trouver la valeur cherch\u00e9e.
Exercice
\u00c9nonc\u00e9Conclusion :
C'est le nombre de puissances de 2 que contient le nombre \\(N\\) de termes de la liste qui est d\u00e9terminant dans la complexit\u00e9 de l'algorithme.
Ce nombre s'appelle le logarithme de base 2 et se note \\(\\log_2(N)\\).
On dit que l'algorithme de dichotomie a une vitesse logarithmique. On rencontrera parfois la notation \\(O(\\log_2(n))\\).
Complexit\u00e9 de la dichotomie
La recherche dichotomique se fait avec une complexit\u00e9 logarithmique.
Cette complexit\u00e9 est bien meilleure qu'une complexit\u00e9 lin\u00e9aire. Le nombre d'op\u00e9rations \u00e0 effectuer est tr\u00e8s peu sensible \u00e0 la taille des donn\u00e9es d'entr\u00e9e, ce qui en fait un algorithme tr\u00e8s efficace.
"},{"location":"T4_Algorithmique/4.5_Dichotomie/cours/#3-experiences-et-comparaison-des-vitesses-dexecution","title":"3. Exp\u00e9riences et comparaison des vitesses d'ex\u00e9cution","text":""},{"location":"T4_Algorithmique/4.5_Dichotomie/cours/#avec-une-liste-contenant-100-000-valeurs","title":"Avec une liste contenant 100 000 valeurs","text":"# cette ligne de code permet de transformer le contenu du fichier input_centmille.txt\n# en une liste L de 100 000 valeurs.\n\nL = open(\"data/input_centmille.txt\",'r').read().split('\\n')\n
Mesurons le temps n\u00e9cessaire pour trouver l'indice de la derni\u00e8re valeur de la liste (qui est 299474) avec la m\u00e9thode de balayage (m\u00e9thode 1) :
%timeit trouve(L, 299474)\n
4.43 ms \u00b1 86.1 \u00b5s per loop (mean \u00b1 std. dev. of 7 runs, 100 loops each)\n
Mesurons le temps n\u00e9cessaire pour trouver l'indice de la derni\u00e8re valeur de la liste (qui est 299474) avec la m\u00e9thode par dichotomie (m\u00e9thode 2) :
%timeit trouve_dicho(L, 299474)\n
3.21 \u00b5s \u00b1 19.6 ns per loop (mean \u00b1 std. dev. of 7 runs, 100000 loops each)\n
Comparaison des deux m\u00e9thodes : l'algorithme dichotomique est bien plus rapide que l'algorithme de balayage (la diff\u00e9rence d'ordre de grandeur est de \\(10^3\\), qui correspond bien \u00e0 l'ordre de grandeur de \\(\\frac{n}{\\log(n)}\\) lorsque \\(n\\) vaut \\(10^5\\)).
"},{"location":"T4_Algorithmique/4.5_Dichotomie/cours/#avec-une-liste-contenant-1-000-000-valeurs-soit-10-fois-plus-que-la-liste-precedente","title":"Avec une liste contenant 1 000 000 valeurs (soit 10 fois plus que la liste pr\u00e9c\u00e9dente)","text":"# ce code permet de transformer le contenu du fichier million.txt en une liste L de 1 000 000 valeurs.\nf = open(\"data/input_million.txt\",'r')\nl = f.readlines()\nL = []\nfor k in l :\n L.append(int(k[:-1]))\n
Mesurons le temps n\u00e9cessaire pour trouver l'indice de la derni\u00e8re valeur de la liste (qui est 2999306) avec la m\u00e9thode de balayage (m\u00e9thode 1) :
%timeit trouve(L, 2999306)\n
46.9 ms \u00b1 615 \u00b5s per loop (mean \u00b1 std. dev. of 7 runs, 10 loops each)\n
Mesurons le temps n\u00e9cessaire pour trouver l'indice de la derni\u00e8re valeur de la liste (qui est 2999306) avec la m\u00e9thode par dichotomie (m\u00e9thode 2) :
%timeit trouve_dicho(L, 2999306)\n
3.04 \u00b5s \u00b1 39.4 ns per loop (mean \u00b1 std. dev. of 7 runs, 100000 loops each)\n
Comparaison des deux m\u00e9thodes : l'algorithme dichotomique est toujours bien plus rapide que l'algorithme de balayage (la diff\u00e9rence d'ordre de grandeur est de \\(10^4\\), qui correspond bien \u00e0 l'ordre de grandeur de \\(\\frac{n}{\\log(n)}\\) lorsque \\(n\\) vaut \\(10^6\\)).
"},{"location":"T4_Algorithmique/4.5_Dichotomie/cours/#influence-de-la-taille-de-la-liste-sur-la-vitesse-de-chaque-methode","title":"Influence de la taille de la liste sur la vitesse de chaque m\u00e9thode :","text":"Remarque : Il ne faut toutefois pas oublier que la m\u00e9thode dichotomique, bien plus rapide, n\u00e9cessite que la liste ait \u00e9t\u00e9 auparavant tri\u00e9e. Ce qui rajoute du temps de calcul ! (cf tri par insertion ou tri par s\u00e9lection )
"},{"location":"T4_Algorithmique/4.5_Dichotomie/intro_cours/","title":"Vers la recherche dichotomique","text":"Code \u00e0 trousdef recherche_dichotomique(lst, val) :\n
Code \u00e0 trous def recherche_dichotomique(lst, val) :\n indice_debut = ...\n indice_fin = ...\n while ... <= ... :\n ... = (... + ...) // 2 \n ... = lst[...] \n if ... == ... : \n return ...\n if valeur_centrale < ... : \n ... = ... + ...\n else :\n ... = ... - ...\n return None \n
Code \u00e0 trous def recherche_dichotomique(lst, val) :\n indice_debut = ...\n indice_fin = ...\n while ... <= ... :\n indice_centre = (... + ...) // 2 \n ... = lst[...] \n if valeur_centrale == ... : \n return ...\n if valeur_centrale < ... : \n ... = ... + 1\n else :\n ... = ... - 1\n return None \n
Code \u00e0 trous def recherche_dichotomique(lst, val) :\n indice_debut = ...\n indice_fin = ...\n while indice_debut <= ... :\n indice_centre = (... + ...) // 2 \n valeur_centrale = lst[...] \n if valeur_centrale == ... : \n return indice_centre\n if valeur_centrale < ... : \n indice_debut = ... + 1\n else :\n indice_fin = ... - 1\n return None\n
"},{"location":"T4_Algorithmique/4.6_Algorithmes_gloutons/cours/","title":"4.6 Algorithmes gloutons","text":"en anglais : greedy algorithms
D\u00e9finition
Un algorithme est qualifi\u00e9 de glouton si le probl\u00e8me qu'il essaie de r\u00e9soudre est d\u00e9compos\u00e9 en une succession de probl\u00e8mes identiques pour lesquels l'algorithme va chercher une solution optimale.
La question (presque philosophique) est :
Lorsqu'on fait \u00e0 chaque \u00e9tape le meilleur choix possible, est-ce que la solution finale \u00e0 laquelle on arrive est la meilleure possible ?
Formul\u00e9 autrement :
Est-ce que faire le meilleur choix \u00e0 chaque \u00e9tape nous assure le meilleur choix global ?
"},{"location":"T4_Algorithmique/4.6_Algorithmes_gloutons/cours/#1-exemples-dalgorithmes-gloutons","title":"1. Exemples d'algorithmes gloutons","text":""},{"location":"T4_Algorithmique/4.6_Algorithmes_gloutons/cours/#11-un-plus-court-chemin","title":"1.1 Un plus court chemin ?","text":"La philosophie de l'algorithme glouton implique qu'\u00e0 chaque \u00e9tape, vous allez vous diriger vers le point le plus proche.
Quel est alors le parcours final ?
R\u00e9ponseVoil\u00e0 ce que donnerait l'algorithme glouton :
Ce chemin est-il optimal ?
R\u00e9ponseNon ! Celui ci-dessous est meilleur :
Le fait d'avoir privil\u00e9gi\u00e9 \u00e0 chaque \u00e9tape le meilleur choix local nous a emp\u00each\u00e9 de voir le meilleur choix global.
"},{"location":"T4_Algorithmique/4.6_Algorithmes_gloutons/cours/#12-remplir-un-rectangle-avec-des-carres","title":"1.2 Remplir un rectangle avec des carr\u00e9s","text":"(d'apr\u00e8s S.Tummarello et E.Buonocore)
On consid\u00e8re un rectangle de dimension 11 sur 13 (figure 0). On veut remplir ce rectangle avec le minimum de carr\u00e9s.
Un algorithme glouton va chercher \u00e0 positionner d'abord le plus grand carr\u00e9 possible (figure 1).
C'est une strat\u00e9gie efficace (8 carr\u00e9s n\u00e9cessaires), mais qui n'est pas optimale : la figure 2 pr\u00e9sente un pavage avec seulement 6 carr\u00e9s.
Encore une fois, la solution gloutonne n'est pas la solution optimale.
Est-ce qu'un algorithme glouton va toujours passer \u00e0 c\u00f4t\u00e9 de la solution optimale ? Non ! Il arrive aussi qu'il donne la solution optimale. Changeons le rectangle initial en un rectangle de 10 sur 15 :
Dans cette situation, l'algorithme glouton nous am\u00e8ne \u00e0 la solution optimale.
"},{"location":"T4_Algorithmique/4.6_Algorithmes_gloutons/cours/#conclusion","title":"Conclusion","text":"Un algorithme glouton est une m\u00e9thode rapide et souvent efficace, mais qui ne garantit pas l'optimalit\u00e9 de la solution trouv\u00e9e.
La succession de meilleurs choix LOCAUX va nous amener \u00e0 une bonne solution GLOBALE, mais ne nous garantit pas d'arriver \u00e0 la solution optimale.
"},{"location":"T4_Algorithmique/4.6_Algorithmes_gloutons/cours/#2-le-probleme-du-rendu-de-monnaie","title":"2. Le probl\u00e8me du rendu de monnaie","text":"Nous allons travailler avec des pi\u00e8ces (ou billets) de 1, 2, 5, 10, 20, 50, 100, 200 euros.
L'objectif est de cr\u00e9er un programme renvoyant, pour une somme somme_a_rendre
entr\u00e9e en param\u00e8tre, la combinaison utilisant un minimum de pi\u00e8ces ou de billets pour fabriquer la somme somme_a_rendre
.
Par exemple, lorsque vous payez avec 20 \u20ac un objet co\u00fbtant 11 \u20ac, vous pr\u00e9f\u00e9rez qu'on vous rende vos 9 \u20ac de monnaie par \\(9 = 5 + 2 + 2\\) plut\u00f4t que par \\(9=2+2+2+1+1+1\\)
La r\u00e9solution de ce probl\u00e8me peut se faire de mani\u00e8re gloutonne : \u00e0 chaque \u00e9tape, vous allez essayer de rendre la plus grosse pi\u00e8ce (ou billet) possible.
Activit\u00e9 de d\u00e9couverte de l'algorithme
"},{"location":"T4_Algorithmique/4.6_Algorithmes_gloutons/cours/#21-solution-du-probleme","title":"2.1 Solution du probl\u00e8me","text":"Rendu de monnaie
def rendu(somme_a_rendre):\n pieces = [200, 100, 50, 20, 10, 5, 2, 1]\n solution = []\n i = 0 # (1)\n while somme_a_rendre > 0:\n if pieces[i] <= somme_a_rendre : # (2) \n solution.append(pieces[i]) # (3) \n somme_a_rendre = somme_a_rendre - pieces[i] # (4)\n else :\n i += 1 # (5) \n return solution\n
solution
Utilisation : rendu(13)
doit renvoyer [10, 2, 1]
>>> rendu(13)\n [10, 2, 1]\n>>> rendu(58)\n [50, 5, 2, 1]\n
"},{"location":"T4_Algorithmique/4.6_Algorithmes_gloutons/cours/#22-une-solution-optimale","title":"2.2 Une solution optimale ?","text":"Imaginons qu'il n'y ait plus de pi\u00e8ces de 10 et 5 euros. Faites fonctionner votre algorithme pour la somme de 63 euros.
>>> rendu(63)\n [50, 2, 2, 2, 2, 2, 2, 1]\n
Damned ! Mais ce n'est pas une solution optimale ! [20, 20, 20, 2, 1]
serait bien mieux.
Moralit\u00e9 : Lors d'un rendu de monnaie, l'algorithme glouton n'est optimal que sous certaines conditions, ce qui est un peu d\u00e9cevant. Un syst\u00e8me de monnaie qui rend l'algorithme glouton est dit canonique. Il est difficile de caract\u00e9riser math\u00e9matiquement si un syst\u00e8me de monnaie est canonique ou pas.
"},{"location":"T4_Algorithmique/4.6_Algorithmes_gloutons/cours/#3-le-probleme-du-sac-a-dos-knapsack-problem","title":"3. Le probl\u00e8me du sac \u00e0 dos (Knapsack Problem)","text":"Le probl\u00e8me est celui-ci : vous disposez d'un sac d'une contenance limit\u00e9e (sur le dessin ci-dessus, 15kg) dans lequel vous allez mettre des objets qui ont un certain poids et une certaine valeur. Vous souhaitez maximiser la valeur totale des objets que vous mettez dans votre sac. Evidemment, la somme de leur masse ne doit pas d\u00e9passer 15 kg.
Ce probl\u00e8me (de la cat\u00e9gorie des probl\u00e8me dits d'analyse combinatoire) malgr\u00e9 sa simplicit\u00e9 est un probl\u00e8me majeur d'optimisation.
O\u00f9 en est-on de la recherche acad\u00e9mique sur le probl\u00e8me du sac \u00e0 dos ?
Actuellement :
Supposons qu'on dispose d'une liste \u00a0mylist = [[\"A\",3], [\"B\",2], [\"C\",8]]
.
Comment classer les \u00e9l\u00e9ments de cette liste par leur deuxi\u00e8me \u00e9l\u00e9ment ???
Nous allons proc\u00e9der en 2 temps.
"},{"location":"T4_Algorithmique/4.6_Algorithmes_gloutons/cours/#311-une-fonction-qui-renvoie-le-deuxieme-element","title":"3.1.1 Une fonction qui renvoie le deuxi\u00e8me \u00e9l\u00e9ment","text":"Cr\u00e9ons une fonction qui renvoie le deuxi\u00e8me \u00e9l\u00e9ment d'un objet liste
:
def deuxieme(lst) :\n return lst[1]\n
Utilisation :
>>> simpsons = ['Bart', 'Lisa', 'Maggie']\n>>> deuxieme(simpsons)\n 'Lisa'\n
"},{"location":"T4_Algorithmique/4.6_Algorithmes_gloutons/cours/#312-tri-de-la-liste-grace-a-cette-fonction-deuxieme","title":"3.1.2 Tri de la liste gr\u00e2ce \u00e0 cette fonction deuxieme
","text":"Nous allons utiliser la fonction sorted
, qui prend en param\u00e8tre une liste \u00e0 trier et une fonction de tri.
>>> mylist = [[\"A\", 3], [\"B\", 2], [\"C\", 8]]\n>>> mynewlist = sorted(mylist, key = deuxieme, reverse = True)\n>>> mynewlist\n[['C', 8], ['A', 3], ['B', 2]]\n
Cette m\u00e9thode de tri va nous \u00eatre tr\u00e8s utile.
"},{"location":"T4_Algorithmique/4.6_Algorithmes_gloutons/cours/#32-retour-sur-le-probleme-du-sac-a-dos","title":"3.2 Retour sur le probl\u00e8me du sac \u00e0 dos","text":"On consid\u00e8re un sac de 40 kg et les objets suivants :
objet A B C D E F masse (en kg) 13 12 8 10 14 18 valeur (en \u20ac) 700 500 200 300 600 800Quels objets faut-il prendre ?
Strat\u00e9gie gloutonne :
On consid\u00e8re la liste
objets = [[\"A\", 13, 700], [\"B\", 12, 500], [\"C\", 8, 200], [\"D\", 10, 300], [\"E\", 14, 600], [\"F\", 18, 800]]\n
En s'inspirant du 3.1.2, on classe ces objets suivant leur taux de valeur.
\u00e0 vous
objets = [[\"A\", 13, 700], [\"B\", 12, 500], [\"C\", 8, 200], [\"D\", 10, 300], [\"E\", 14, 600], [\"F\", 18, 800]]\n\ndef ratio(objet):\n # renvoie le rapport prix/poids d'un objet\n return objet[2] / objet[1]\n\nobjets_tries = sorted(objets, key = ratio, reverse = True)\n
>>> objets_tries\n [['A', 13, 700],\n ['F', 18, 800],\n ['E', 14, 600],\n ['B', 12, 500],\n ['D', 10, 300],\n ['C', 8, 200]]\n
"},{"location":"T4_Algorithmique/4.6_Algorithmes_gloutons/cours/#322-calcul-de-la-solution-par-methode-gloutonne","title":"3.2.2 Calcul de la solution, par m\u00e9thode gloutonne","text":"\u00e0 vous
objets = [[\"A\", 13, 700], [\"B\", 12, 500], [\"C\", 8, 200], [\"D\", 10, 300], [\"E\", 14, 600], [\"F\", 18, 800]]\n\ndef ratio(objet):\n # renvoie le rapport prix/poids d'un objet\n return objet[2] / objet[1]\n\nobjets_tries = sorted(objets, key = ratio, reverse = True)\n\npoids_max = 40\npoids_sac = 0\n\nbutin = []\n\nfor objet in objets_tries:\n poids_objet = objet[1]\n if poids_objet + poids_sac <= poids_max :\n butin.append(objet[0])\n poids_sac += poids_objet\n
>>> butin\n ['A', 'F', 'C']\n
Il faut donc choisir la combinaison A, F, C. Elle est bien valide (poids 39) et rapporte 1700.
Question (toujours la m\u00eame) :
L'algorithme glouton nous a-t-il donn\u00e9 la solution optimale ? Nous allons pour cela avoir recours \u00e0 la force brute pour tester toutes les combinaisons possibles.
"},{"location":"T4_Algorithmique/4.6_Algorithmes_gloutons/cours/#33-force-brute","title":"3.3 Force brute","text":"objets = [[\"A\", 13, 700], [\"B\", 12, 500], [\"C\", 8, 200], [\"D\", 10, 300], [\"E\", 14, 600], [\"F\", 18, 800]]\npoids_max = 40\n
"},{"location":"T4_Algorithmique/4.6_Algorithmes_gloutons/cours/#331-la-liste-de-tous-les-mots-possibles","title":"3.3.1 La liste de tous les mots possibles","text":"combinaisons = []\nfor i in range(2**len(objets)):\n k = bin(i)[2:]\n s = '0'*(len(objets)-len(k)) + k\n combinaisons.append(s)\n
La liste combinaisons
contient bien les 64 mots possibles (\\(2^6=64\\)) :
>>> combinaisons\n ['000000',\n '000001',\n '000010',\n '000011',\n '000100',\n '000101',\n '000110',\n '000111',\n '001000',\n '001001',\n '001010',\n '001011',\n '001100',\n '001101',\n '001110',\n '001111',\n '010000',\n '010001',\n '010010',\n '010011',\n '010100',\n '010101',\n '010110',\n '010111',\n '011000',\n '011001',\n '011010',\n '011011',\n '011100',\n '011101',\n '011110',\n '011111',\n '100000',\n '100001',\n '100010',\n '100011',\n '100100',\n '100101',\n '100110',\n '100111',\n '101000',\n '101001',\n '101010',\n '101011',\n '101100',\n '101101',\n '101110',\n '101111',\n '110000',\n '110001',\n '110010',\n '110011',\n '110100',\n '110101',\n '110110',\n '110111',\n '111000',\n '111001',\n '111010',\n '111011',\n '111100',\n '111101',\n '111110',\n '111111']\n
valeurs = [] \npoids = []\nfor comb in combinaisons :\n poids_comb = 0\n valeur = 0\n for i in range(len(objets)): \n if comb[i] == '1':\n poids_comb += objets[i][1]\n valeur += objets[i][2]\n if poids_comb > poids_max :\n valeur = 0\n valeurs.append(valeur)\n poids.append(poids_comb)\n\nvaleur_max = max(valeurs)\nmeilleure_comb = combinaisons[valeurs.index(valeur_max)]\npoids_comb = poids[valeurs.index(valeur_max)]\n\nmot_sol = \"\"\nfor k in range(len(meilleure_comb)) :\n if meilleure_comb[k] == '1' :\n mot_sol += objets[k][0]\n
>>> mot_sol\n 'ABE'\n
re-Damned ! La force brute a mis en \u00e9vidence une combinaison meilleure que celle donn\u00e9e par l'algorithme glouton.
En effet la combinaison A-B-E est bien valide (poids total 39) et rapporte 1800, donc 100 de mieux que la solution gloutonne.
Par contre, la force brute est inenvisageable pour si le nombre d'objets est grand, alors que la strat\u00e9gie gloutonne reste tr\u00e8s rapide.
"},{"location":"T4_Algorithmique/4.6_Algorithmes_gloutons/cours/#conclusion_1","title":"Conclusion","text":"La strat\u00e9gie gloutonne donne tr\u00e8s rapidement des solutions satisfaisantes mais pas forc\u00e9ment optimales. Pour beaucoup de probl\u00e8mes (dont le probl\u00e8me du sac \u00e0 dos), la recherche d'une solution optimale sans passer par la force brute semble impossible (mais n'est pas d\u00e9montr\u00e9e). Dans ce cas-l\u00e0, la strat\u00e9gie gloutonne peut \u00eatre employ\u00e9e pour avoir vite et bien une solution convenable, m\u00eame si peut-\u00eatre non optimale. On dit que la strat\u00e9gie gloutonne est une heuristique de r\u00e9solution. On sait que ce n'est pas forc\u00e9ment optimal, mais faute de mieux, on s'en contente...
"},{"location":"T4_Algorithmique/4.6_Algorithmes_gloutons/intro_rendu/","title":"Vers l'algorithme de rendu de monnaie","text":"On veut coder la fonction rendu
qui prend pour param\u00e8tre un entier positif somme_a_rendre
et qui renvoie la liste des pi\u00e8ces \u00e0 donner.
Les pieces disponibles (en quantit\u00e9 illimit\u00e9e) sont stock\u00e9es dans une variable pieces = [200, 100, 50, 20, 10, 5, 2, 1]
.
Utilisation : rendu(13)
doit renvoyer [10, 2, 1]
>>> rendu(13)\n [10, 2, 1]\n>>> rendu(58)\n [50, 5, 2, 1]\n
Code \u00e0 trous def rendu(somme_a_rendre):\n pieces = [200, 100, 50, 20, 10, 5, 2, 1]\n solution = []\n ...\n ...\n ...\n ...\n ...\n ...\n ... \n return solution \n
Code \u00e0 trous def rendu(somme_a_rendre):\n pieces = [200, 100, 50, 20, 10, 5, 2, 1]\n solution = []\n i = ... \n while ... > ...:\n if ... <= ... : \n ....append(...) \n ... = ... - ... \n else :\n ... += ... \n return solution \n
Code \u00e0 trous def rendu(somme_a_rendre):\n pieces = [200, 100, 50, 20, 10, 5, 2, 1]\n solution = []\n i = 0 \n while ... > ...:\n if pieces[i] <= ... : \n solution.append(...) \n somme_a_rendre = ... - ... \n else :\n ... += ... \n return solution \n
Code \u00e0 trous def rendu(somme_a_rendre):\n pieces = [200, 100, 50, 20, 10, 5, 2, 1]\n solution = []\n i = 0 \n while somme_a_rendre > ...:\n if pieces[i] <= somme_a_rendre : \n solution.append(...) \n somme_a_rendre = ... - ... \n else :\n i += 1 \n return solution\n
"},{"location":"T4_Algorithmique/4.7_Algorithme_KNN/07_Algorithme_KNN/","title":"M\u00e9thode du K-Nearest-Neighbours (KNN), aka les k-plus-proches-voisins","text":"La m\u00e9thode KNN est une m\u00e9thode simple et efficace de classification. La classification est un enjeu majeur de l'Intelligence Artificielle : - la cam\u00e9ra d'une voiture autonome per\u00e7oit un panneau, mais quel est ce panneau ? - un grain de beaut\u00e9 est pris en photo par un dermatologue, ce grain de beaut\u00e9 est-il canc\u00e9reux ? - ...
La m\u00e9thode du KNN va trouver quels sont, dans une base de donn\u00e9es d\u00e9j\u00e0 bien remplie et labell\u00e9e, les k-objets (les 6 objets si \\(k=6\\) par exemple) qui se rapprochent le plus de l'objet \u00e0 classifier. En prenant ensuite la caract\u00e9ristique la plus fr\u00e9quente parmi ces 6 objets, on devine alors dans quelle cat\u00e9gorie notre objet doit se classer.
Notre objectif : Nous allons reprendre le jeu de donn\u00e9es sur les joueurs du top14 utilis\u00e9 ici dans le cours \u00abTrier des donn\u00e9es\u00bb
Question : si on croise une personne nous disant qu'elle veut jouer en top14, et qu'elle nous donne son poids et sa taille, peut-on lui pr\u00e9dire \u00e0 quel poste elle devrait jouer ?
Dans toute id\u00e9e de classification il y a l'id\u00e9e de distance. Il faut comprendre la distance comme une mesure de la diff\u00e9rence.
Comment mesurer la diff\u00e9rence physique entre deux joueurs de rugby ?
import pandas as pd #import du module pandas, abr\u00e9g\u00e9 classiquement par \"pd\"\n
df = pd.read_csv('data/top14.csv', encoding = 'utf-8')\n
"},{"location":"T4_Algorithmique/4.7_Algorithme_KNN/07_Algorithme_KNN/#resultat-attendu","title":"R\u00e9sultat attendu :","text":"Il faut cr\u00e9er une fonction knn()
qui prend en argument poids
et taille
, sont les caract\u00e9ristiques du nouveau joueur. La fonction doit renvoyer une cha\u00eene de caract\u00e8re correspondant au poste auquel elle est susceptible de jouer.
Exemple :
def knn(poids, taille):\n df['distance']=(df['Taille']-taille)**2+(df['Poids']-poids)**2\n newdf = df.sort_values(by='distance', ascending=True)\n newdftri = newdf.head(6) #on prend les 6 joueurs les plus proches physiquement\n sol = newdftri['Poste'].describe().top\n return sol\n
knn(93,188)\n
'Ailier'\n
"},{"location":"T4_Algorithmique/4.7_Algorithme_KNN/07_Algorithme_KNN/#influence-du-parametre-k","title":"Influence du param\u00e8tre \\(k\\)","text":"Dans le code pr\u00e9c\u00e9dent, on a travaill\u00e9 avec \\(k=6\\) et c'est le poste majoritaire parmi les 6 joueurs les plus proches qui a \u00e9t\u00e9 donn\u00e9 par l'algorithme. Modifions l\u00e9g\u00e8rement la fonction knn()
afin d'observer l'influence du param\u00e8tre \\(k\\) sur la pr\u00e9diction :
def knn(poids, taille, k):\n df['distance']=(df['Taille']-taille)**2+(df['Poids']-poids)**2\n newdf = df.sort_values(by='distance', ascending=True)\n newdftri = newdf.head(k) #on prend les k joueurs les plus proches physiquement\n sol = newdftri['Poste'].describe().top\n return sol\n\nfor k in range(1,20):\n print(knn(93,188,k))\n
Centre\nAilier\nAilier\nAilier\nAilier\nAilier\nAilier\nAilier\nAilier\nAilier\nAilier\nAilier\nAilier\nAilier\nAilier\nAilier\nAilier\nAilier\nAilier\n
On s'aper\u00e7oit que la pr\u00e9diction est tr\u00e8s stable... sauf si \\(k=1\\) ! Il se trouve qu'un joueur poss\u00e8de exactement ces caract\u00e9ristiques physiques (Pierre-Louis BARASSI) et qu'il joue Centre :
df['distance']=(df['Taille']-188)**2+(df['Poids']-93)**2\nnewdf = df.sort_values(by='distance', ascending=True)\nnewdf.head(10)\n
Equipe Nom Poste Date de naissance Taille Poids distance 314 Lyon Pierre-Louis BARASSI Centre 22/04/1998 188 93 0 461 Pau Vincent PINTO Ailier 10/04/1999 187 93 1 527 Toulon St\u00e9phane ONAMB\u00c9L\u00c9 3\u00e8me ligne 12/02/1993 188 94 1 202 Castres Geoffrey PALIS Arri\u00e8re 08/07/1991 189 93 1 196 Castres Armand BATLLE Ailier 12/04/1987 188 92 1 585 Toulouse Th\u00e9o BELAN Centre 15/11/1992 187 94 2 242 Clermont Samuel EZEALA Ailier 11/12/1999 187 94 2 502 Racing92 Simon ZEBO Ailier 16/03/1990 187 94 2 133 Brive Esteban ABADIE 3\u00e8me ligne 01/12/1997 188 95 4 369 Montpellier Benjamin FALL Arri\u00e8re 03/03/1989 186 93 4 On peut s'apercevoir aussi que jusqu'\u00e0 \\(k=5\\), aucun poste n'est majoritaire : la pr\u00e9diction pourrait aussi bien renvoyer Centre, 3\u00e8me ligne, ou Arri\u00e8re. Ce n'est que gr\u00e2ce \u00e0 l'ordre alphab\u00e9tique que la r\u00e9ponse renvoy\u00e9e est \u00abAilier\u00bb. Par contre, d\u00e8s que \\(k \\geqslant 5\\), le poste d'Ailier est bien majoritaire parmi les \\(k\\) plus proches voisins.
\n
"},{"location":"T4_Algorithmique/4.7_Algorithme_KNN/cours/","title":"4.7 Algorithme des KNN","text":"Algorithme des K-Nearest-Neighbours (KNN), aka les k-plus-proches-voisins
La m\u00e9thode KNN est une m\u00e9thode simple et efficace de classification. La classification est un enjeu majeur de l'Intelligence Artificielle :
La m\u00e9thode du KNN va trouver quels sont, dans une base de donn\u00e9es d\u00e9j\u00e0 bien remplie et labell\u00e9e, les k-objets (les 6 objets si \\(k=6\\) par exemple) qui se rapprochent le plus de l'objet \u00e0 classifier. En prenant ensuite la caract\u00e9ristique la plus fr\u00e9quente parmi ces 6 objets, on devine alors dans quelle cat\u00e9gorie notre objet doit se classer.
"},{"location":"T4_Algorithmique/4.7_Algorithme_KNN/cours/#1-objectif","title":"1. Objectif","text":"Nous allons reprendre le jeu de donn\u00e9es sur les joueurs du Top14 utilis\u00e9 dans le cours \u00abTrier des donn\u00e9es\u00bb
Nous souhaitons pouvoir r\u00e9pondre \u00e0 cette question :
Question
Si on croise une personne (qu'on appelera joueur X) nous disant qu'elle veut jouer en Top14, et qu'elle nous donne son poids et sa taille, peut-on lui pr\u00e9dire \u00e0 quel poste elle devrait jouer ?
Nous devons donc cr\u00e9er une fonction conseil_poste
qui prend en argument poids
et taille
, qui sont les caract\u00e9ristiques du joueur X. Cette fonction prendra aussi en param\u00e8tre un nombre k
qui sera le nombre de voisins utilis\u00e9s pour d\u00e9terminer le poste conseill\u00e9.
La fonction doit renvoyer une cha\u00eene de caract\u00e8re correspondant au poste auquel on lui conseille de jouer.
Il va falloir pour cela classer tous les joueurs du Top14 suivant leur proximit\u00e9 morphologique avec notre joueur X, et prendre parmi les k
premiers joueurs le poste majoritaire.
distance
morphologique","text":"Dans toute id\u00e9e de classification il y a l'id\u00e9e de distance. Il faut comprendre la distance comme une mesure de la diff\u00e9rence.
Comment mesurer la diff\u00e9rence physique entre deux joueurs de rugby ?
Fonction distance
\u00c9crire une fonction distance
qui re\u00e7oit en param\u00e8tres :
poids
: le poids du joueur Xtaille
: la taille du joueur Xplayer
: un joueur de la liste joueurs
et qui renvoie la distance morphologique du joueur X avec player
.
Exemple d'utilisation :
>>> distance(93, 190, joueurs[34])\n445\n
Correction def distance(poids, taille, player):\n p = int(player['Poids'])\n t = int(player['Taille'])\n return (poids-p)**2 + (taille-t)**2\n
"},{"location":"T4_Algorithmique/4.7_Algorithme_KNN/cours/#3-classement-des-joueurs-suivant-leur-proximite-morphologique","title":"3. Classement des joueurs suivant leur proximit\u00e9 morphologique","text":"De la m\u00eame mani\u00e8re qu'on avait class\u00e9 les joueurs suivant leur IMC, on peut les classer suivant leur proximit\u00e9 morphologique avec le joueur X.
"},{"location":"T4_Algorithmique/4.7_Algorithme_KNN/cours/#31-fonction-second","title":"3.1 Fonctionsecond
","text":"Fonction second
\u00c9crire une fonction second
qui re\u00e7oit en param\u00e8tres :
couple
: un couple de valeurset qui renvoie le deuxi\u00e8me \u00e9l\u00e9ment du couple.
Exemple d'utilisation :
>>> cpl = (\"vendredi\", 13)\n>>> second(cpl)\n13\n
Correction def second(cpl):\n return cpl[1]\n
"},{"location":"T4_Algorithmique/4.7_Algorithme_KNN/cours/#32-classement-des-k-plus-proches-joueurs","title":"3.2 Classement des k plus proches joueurs","text":"Fonction classement_k_joueurs
\u00c9crire une fonction classement_k_joueurs
qui re\u00e7oit en param\u00e8tres :
poids
: le poids du joueur Xtaille
: la taille du joueur Xk
: le nombre de joueurs les plus proches que l'on veut garderet qui renvoie une liste contenant les k joueurs class\u00e9s suivant leur proximit\u00e9 morphologique avec le joueur X.
Exemple d'utilisation :
>>> classement_k_joueurs(85, 186, 3)\n[{'Equipe': 'Bordeaux', 'Nom': 'Geoffrey CROS', 'Poste': 'Arri\u00e8re', 'Date de naissance': '08/03/1997', 'Taille': '185', 'Poids': '85'}, {'Equipe': 'Toulouse', 'Nom': 'Romain NTAMACK', 'Poste': 'Ouverture', 'Date de naissance': '01/05/1999', 'Taille': '186', 'Poids': '84'}, {'Equipe': 'Bayonne', 'Nom': 'Manuel ORDAS', 'Poste': 'Ouverture', 'Date de naissance': '21/02/1998', 'Taille': '186', 'Poids': '83'}]\n
Correction def classement_k_joueurs(poids, taille):\n couples = []\n for player in joueurs:\n couples.append((player, distance(poids, taille, player)))\n couples_tries = sorted(couples, key=second)\n joueurs_classes = [couple[0] for couple in couples_tries]\n return joueurs_classes[:k]\n
"},{"location":"T4_Algorithmique/4.7_Algorithme_KNN/cours/#4-recherche-du-poste-le-plus-represente","title":"4. Recherche du poste le plus repr\u00e9sent\u00e9","text":""},{"location":"T4_Algorithmique/4.7_Algorithme_KNN/cours/#41-dictionnaire-doccurence-des-postes","title":"4.1 Dictionnaire d'occurence des postes","text":"Fonction occurence
\u00c9crire une fonction occurence
qui re\u00e7oit en param\u00e8tres :
joueurs
: une liste de joueurset qui renvoie le dictionnaire compos\u00e9 diff\u00e9rents postes de ces joueurs, et du nombre de fois o\u00f9 ils apparaissent dans la liste joueurs
.
Exemple d'utilisation :
>>> occurence(joueurs)\n{'Pilier': 110, 'Talonneur': 50, '2\u00e8me ligne': 74, '3\u00e8me ligne': 111, 'M\u00eal\u00e9e': 42, 'Ouverture': 38, 'Centre': 71, 'Ailier': 64, 'Arri\u00e8re': 35}\n
Correction def occurence(joueurs):\n occ = {}\n for player in joueurs:\n if player['Poste'] in occ:\n occ[player['Poste']] += 1\n else:\n occ[player['Poste']] = 1\n return occ\n
"},{"location":"T4_Algorithmique/4.7_Algorithme_KNN/cours/#42-tri-dun-dictionnaire","title":"4.2 Tri d'un dictionnaire","text":"Fonction cle_max
\u00c9crire une fonction cle_max
qui re\u00e7oit en param\u00e8tre :
d
: un dictionnaire dont les cl\u00e9s sont des chaines de caract\u00e8re et les valeurs sont des nombres.et qui renvoie la cl\u00e9 associ\u00e9e \u00e0 la valeur maximale.
Exemple d'utilisation :
>>> d = {\"lundi\":13, \"mardi\":9, \"mercredi\":18, \"jeudi\":4}\n>>> cle_max(d)\n'mercredi'\n
Correction def cle_max(d):\n maxi = 0\n for key in d:\n if d[key] > maxi:\n maxi = d[key]\n key_max = key\n return key_max\n
"},{"location":"T4_Algorithmique/4.7_Algorithme_KNN/cours/#43-fonction-conseil_poste","title":"4.3 Fonction conseil_poste
","text":"Fonction conseil_poste
\u00c9crire une fonction conseil_poste
qui re\u00e7oit en param\u00e8tres :
poids
: le poids du joueur Xtaille
: la taille du joueur Xk
: le nombre de joueurs les plus proches sur lequel on se base pour faire la pr\u00e9dictionet qui renvoie le poste le plus compatible avec la morphologie de X.
Exemple d'utilisation :
>>> conseil_poste(70, 170, 6)\n'M\u00eal\u00e9e'\n>>> conseil_poste(120, 210, 6)\n'2\u00e8me ligne'\n
Correction def conseil_poste(poids, taille, k):\n joueurs_classes = classement_k_joueurs(poids, taille, k)\n dico = occurence(joueurs_classes)\n poste_conseille = cle_max(dico)\n return poste_conseille\n
Faire varier les diff\u00e9rents param\u00e8tres pour observer leur r\u00f4le respectif.
"},{"location":"T5_Traitement_de_donnees/sommaire/","title":"Th\u00e8me 5 : Traitement de donn\u00e9es","text":"Les fichiers CSV (pour Comma Separated Values) sont des fichiers-texte (ils ne contiennent aucune mise en forme) utilis\u00e9s pour stocker des donn\u00e9es, s\u00e9par\u00e9es par des virgules (ou des points-virgules, ou des espaces...). Il n'y a pas de norme officielle du CSV.
"},{"location":"T5_Traitement_de_donnees/5.1_Manipulation_csv/cours/#1-ouverture-dun-fichier-csv-par-des-logiciels-classiques","title":"1. Ouverture d'un fichier CSV par des logiciels classiques","text":"L'utilisation d'un tableur peut \u00eatre d\u00e9licate lorsque le fichier CSV comporte un tr\u00e8s grand nombre de lignes. Python permet de lire et d'extraire des informations d'un fichier CSV m\u00eame tr\u00e8s volumineux, gr\u00e2ce \u00e0 des modules d\u00e9di\u00e9s, comme le bien-nomm\u00e9 csv
(utilis\u00e9 ici) ou bien pandas
(qui sera vu plus tard).
Le script suivant :
import csv \nf = open('exemple.csv', \"r\", encoding = 'utf-8') # le \"r\" signifie \"read\", le fichier est ouvert en lecture seule\ndonnees = csv.reader(f) # donnees est un objet (sp\u00e9cifique au module csv) qui contient des lignes\n\nfor ligne in donnees: \n print(ligne)\n\nf.close() # toujours fermer le fichier !\n
donne :
['Pr\u00e9nom', 'Nom', 'Email', 'SMS']\n['John', 'Smith', 'john@example.com', '33123456789']\n['Harry', 'Pierce', 'harry@example.com', '33111222222']\n['Howard', 'Paige', 'howard@example.com', '33777888898']\n
Probl\u00e8mes
donnees
n'est pas exploitable en l'\u00e9tat. Ce n'est pas une structure connue.Au lieu d'utiliser la fonction csv.reader()
, utilisons csv.DictReader()
. Comme son nom l'indique, elle renverra une variable contenant des dictionnaires.
Le script suivant :
import csv\nf = open('exemple.csv', \"r\", encoding = 'utf-8')\ndonnees = csv.DictReader(f)\n\nfor ligne in donnees:\n print(dict(ligne))\n\nf.close()\n
donne
{'Pr\u00e9nom': 'John', 'Nom': 'Smith', 'Email': 'john@example.com', 'SMS': '33123456789'}\n{'Pr\u00e9nom': 'Harry', 'Nom': 'Pierce', 'Email': 'harry@example.com', 'SMS': '33111222222'}\n{'Pr\u00e9nom': 'Howard', 'Nom': 'Paige', 'Email': 'howard@example.com', 'SMS': '33777888898'}\n
C'est mieux ! Les donn\u00e9es sont maintenant des dictionnaires. Mais nous avons juste \u00e9num\u00e9r\u00e9 3 dictionnaires. Comment r\u00e9-acc\u00e9der au premier d'entre eux, celui de John Smith ? Essayons :
>>> donnees[0]\n\n ---------------------------------------------------------------------------\n\n TypeError Traceback (most recent call last)\n\n <ipython-input-3-9914ab00321e> in <module>\n ----> 1 donnees[0]\n\n\n TypeError: 'DictReader' object does not support indexing\n
"},{"location":"T5_Traitement_de_donnees/5.1_Manipulation_csv/cours/#23-une-liste-de-dictionnaires","title":"2.3 Une liste de dictionnaires","text":"Nous allons donc cr\u00e9er une liste de dictionnaires.
Le script suivant :
import csv\nf = open('exemple.csv', \"r\", encoding = 'utf-8')\ndonnees = csv.DictReader(f)\namis = []\nfor ligne in donnees:\n amis.append(dict(ligne))\n\nf.close()\n
permet de faire ceci :
>>> amis\n\n [{'Pr\u00e9nom': 'John',\n 'Nom': 'Smith',\n 'Email': 'john@example.com',\n 'SMS': '33123456789'},\n {'Pr\u00e9nom': 'Harry',\n 'Nom': 'Pierce',\n 'Email': 'harry@example.com',\n 'SMS': '33111222222'},\n {'Pr\u00e9nom': 'Howard',\n 'Nom': 'Paige',\n 'Email': 'howard@example.com',\n 'SMS': '33777888898'}]\n\n>>> print(amis[0]['Email'])\n john@example.com\n\n>>> print(amis[2]['Nom'])\n Paige\n
"},{"location":"T5_Traitement_de_donnees/5.1_Manipulation_csv/cours/#3-un-fichier-un-peu-plus-interessant-les-joueurs-de-rugby-du-top14","title":"3. Un fichier un peu plus int\u00e9ressant : les joueurs de rugby du TOP14","text":"Le fichier top14.csv
contient tous les joueurs du Top14 de rugby, saison 2019-2020, avec leur date de naissance, leur poste, et leurs mensurations.
Ce fichier a \u00e9t\u00e9 g\u00e9n\u00e9r\u00e9 par R\u00e9mi Deniaud, de l'acad\u00e9mie de Bordeaux.
Q1. Stocker dans une variable joueurs
les renseignements de tous les joueurs pr\u00e9sents dans ce fichier csv.
import csv\nf = open('data/top14.csv', \"r\", encoding = 'utf-8')\ndonnees = csv.DictReader(f)\njoueurs = []\nfor ligne in donnees:\n joueurs.append(dict(ligne))\n\nf.close()\n
"},{"location":"T5_Traitement_de_donnees/5.1_Manipulation_csv/cours/#31-premiere-analyse","title":"3.1 Premi\u00e8re analyse","text":"Q2. Combien de joueurs sont pr\u00e9sents dans ce fichier ?
r\u00e9ponse```python
len(joueurs) 595 ```}
Q3. Quel est le nom du joueur n\u00b0486 ?
r\u00e9ponse>>> joueurs[486]['Nom']\n 'Wenceslas LAURET'\n
"},{"location":"T5_Traitement_de_donnees/5.1_Manipulation_csv/cours/#32-extraction-de-donnees-particulieres","title":"3.2 Extraction de donn\u00e9es particuli\u00e8res","text":"Q4. O\u00f9 joue Baptiste SERIN ?
La m\u00e9thode la plus naturelle est de parcourir toute la liste jusqu'\u00e0 trouver le bon joueur, puis d'afficher son \u00e9quipe.
r\u00e9ponse>>> for joueur in joueurs :\n if joueur['Nom'] == 'Baptiste SERIN' :\n print(joueur['Equipe'])\n
Une m\u00e9thode plus efficace est d'utiliser une liste par compr\u00e9hension incluant un test.
r\u00e9ponse>>> clubSerin = [joueur['Equipe'] for joueur in joueurs if joueur['Nom'] == 'Baptiste SERIN']\n>>> clubSerin\n
Q5. Qui sont les joueurs de plus de 140 kg ?
Attention \u00e0 bien convertir en entier la chaine de caract\u00e8re renvoy\u00e9e par la cl\u00e9 Poids
, \u00e0 l'aide de la fonction int()
.
>>> lourds = [(joueur['Nom'], joueur['Poids']) for joueur in joueurs if int(joueur['Poids']) > 140]\n>>> lourds\n
"},{"location":"T5_Traitement_de_donnees/5.1_Manipulation_csv/cours/#4-exploitation-graphique","title":"4. Exploitation graphique","text":"Nous allons utiliser le module Matplotlib pour illustrer les donn\u00e9es de notre fichier csv.
"},{"location":"T5_Traitement_de_donnees/5.1_Manipulation_csv/cours/#41-exemple","title":"4.1 Exemple","text":"import matplotlib.pyplot as plt\nX = [0,1,3,6]\nY = [12,10,7,15]\nplt.plot(X,Y,'ro') # r pour red, o pour un cercle. voir https://matplotlib.org/api/markers_api.html\nplt.show()\n
"},{"location":"T5_Traitement_de_donnees/5.1_Manipulation_csv/cours/#42-application","title":"4.2 Application","text":"Q1. Afficher sur un graphique tous les joueurs de rugby du Top14, en mettant le poids en abscisse et la taille en ordonn\u00e9e.
r\u00e9ponseX = [int(joueur['Poids']) for joueur in joueurs]\nY = [int(joueur['Taille']) for joueur in joueurs]\nplt.plot(X, Y, 'ro') # r pour red, o pour un cercle. voir https://matplotlib.org/api/markers_api.html\nplt.show()\n
Q2. Faire appara\u00eetre ensuite les joueurs \u00e9voluant au poste de Centre en bleu, et les 2\u00e8me lignes en vert.
r\u00e9ponse#tous les joueurs\nX = [int(joueur['Poids']) for joueur in joueurs]\nY = [int(joueur['Taille']) for joueur in joueurs]\nplt.plot(X, Y, 'ro') \n\n#on recolorie les Centres en bleu\nX = [int(joueur['Poids']) for joueur in joueurs if joueur['Poste'] == 'Centre']\nY = [int(joueur['Taille']) for joueur in joueurs if joueur['Poste'] == 'Centre']\nplt.plot(X, Y, 'bo')\n\n#on recolorie les 2\u00e8me ligne en vert\nX = [int(joueur['Poids']) for joueur in joueurs if joueur['Poste'] == '2\u00e8me ligne']\nY = [int(joueur['Taille']) for joueur in joueurs if joueur['Poste'] == '2\u00e8me ligne']\nplt.plot(X, Y, 'go')\n\n\nplt.show()\n
"},{"location":"T5_Traitement_de_donnees/5.2_Trier_des_donnees/cours/","title":"5.2 Trier des donn\u00e9es","text":"Nous reprenons notre fichier de joueurs de rugby du Top14. : top14.csv
import csv\nf = open('top14.csv', \"r\", encoding = 'utf-8')\ndonnees = csv.DictReader(f)\njoueurs = []\nfor ligne in donnees:\n joueurs.append(dict(ligne))\n\nf.close()\n
"},{"location":"T5_Traitement_de_donnees/5.2_Trier_des_donnees/cours/#1-creer-une-fonction-filtre","title":"1. Cr\u00e9er une fonction filtre","text":"L'objectif est de cr\u00e9er une fonction joueursEquipe(equipe)
qui renvoie une liste contentant tous les joueurs de l'\u00e9quipe equipe
. Le param\u00e8tre equipe
sera donn\u00e9e sous forme de cha\u00eene de caract\u00e8res. La valeur renvoy\u00e9e sera de type liste.
Utilisation :
>>> joueursEquipe('Bordeaux')\n[{'Equipe': 'Bordeaux', 'Nom': 'Jefferson POIROT', 'Poste': 'Pilier', 'Date de naissance': '01/11/1992', 'Taille': '181', 'Poids': '117'}, {'Equipe': 'Bordeaux', 'Nom': 'Lasha TABIDZE', 'Poste': 'Pilier', 'Date de naissance': '04/07/1997', 'Taille': '185', 'Poids': '117'}, {'Equipe': 'Bordeaux', 'Nom': 'Laurent DEL.....\n
r\u00e9ponse def joueursEquipe(equipe): \n return [player for player in joueurs if player[\"Equipe\"] == equipe]\n
D\u00e9finir de la m\u00eame mani\u00e8re une fonction joueursPoste(poste)
.
Utilisation :
>>> joueursPoste(\"Talonneur\")\n[{'Equipe': 'Agen', 'Nom': 'Cl\u00e9ment MARTINEZ', 'Poste': 'Talonneur', 'Date de naissance': '14/03/1996', 'Taille': '181', 'Poids': '105'}, {'Equipe': 'Agen', 'Nom': 'Marc BARTHOMEUF', 'Poste': 'T...\n
r\u00e9ponse def joueursPoste(poste): \n return [player for player in joueurs if player[\"Poste\"] == poste]\n
"},{"location":"T5_Traitement_de_donnees/5.2_Trier_des_donnees/cours/#2-utilisation-dune-fonction-de-tri","title":"2. Utilisation d'une fonction de tri","text":""},{"location":"T5_Traitement_de_donnees/5.2_Trier_des_donnees/cours/#21-le-probleme","title":"2.1 Le probl\u00e8me","text":"Comment classer les joueurs suivant leur taille ? La fonction sorted(liste)
est efficace sur les listes : elle renvoie une nouvelle liste tri\u00e9e dans l'ordre croissant.
>>> mylist = [4,2,8,6]\n>>> mynewlist = sorted(mylist)\n>>> print(mynewlist)\n [2, 4, 6, 8]\n
Mais comment trier un dictionnaire ?
>>> test = sorted(joueurs)\n
---------------------------------------------------------------------------\n\nTypeError Traceback (most recent call last)\n\n<ipython-input-14-de081d14a3da> in <module>\n----> 1 test = sorted(joueurs)\n\n\nTypeError: '<' not supported between instances of 'dict' and 'dict'\n
Il est normal que cette tentative \u00e9choue : un dictionnaire poss\u00e8de plusieurs cl\u00e9s diff\u00e9rentes. Ici, plusieurs cl\u00e9s peuvent \u00eatre des crit\u00e8res de tri : la taille, le poids.
"},{"location":"T5_Traitement_de_donnees/5.2_Trier_des_donnees/cours/#22-un-exemple-de-tri-de-dictionnaire","title":"2.2 Un exemple de tri de dictionnaire","text":">>> Simpsons = [{\"Prenom\" : \"Bart\", \"age estim\u00e9\": \"10\"},\n {\"Prenom\" : \"Lisa\", \"age estim\u00e9\": \"8\"},\n {\"Prenom\" : \"Maggie\", \"age estim\u00e9\": \"1\"},\n {\"Prenom\" : \"Homer\", \"age estim\u00e9\": \"38\"},\n {\"Prenom\" : \"Marge\", \"age estim\u00e9\": \"37\"}]\n
>>> def age(personnage):\n return int(personnage[\"age estim\u00e9\"])\n
>>> age(Simpsons[0])\n 10\n
La cr\u00e9ation de cette fonction age()
va nous permettre de sp\u00e9cifier une cl\u00e9 de tri, par le param\u00e8tre key
:
Tri d'un dictionnaire
>>> triSimpsons = sorted(Simpsons, key = age)\n
>>> triSimpsons\n [{'Prenom': 'Maggie', 'age estim\u00e9': '1'},\n {'Prenom': 'Lisa', 'age estim\u00e9': '8'},\n {'Prenom': 'Bart', 'age estim\u00e9': '10'},\n {'Prenom': 'Marge', 'age estim\u00e9': '37'},\n {'Prenom': 'Homer', 'age estim\u00e9': '38'}]\n
On peut aussi inverser l'ordre de tri :
>>> triSimpsons = sorted(Simpsons, key = age, reverse = True)\n>>> triSimpsons\n [{'Prenom': 'Homer', 'age estim\u00e9': '38'},\n {'Prenom': 'Marge', 'age estim\u00e9': '37'},\n {'Prenom': 'Bart', 'age estim\u00e9': '10'},\n {'Prenom': 'Lisa', 'age estim\u00e9': '8'},\n {'Prenom': 'Maggie', 'age estim\u00e9': '1'}]\n
Exercice 1
\u00c9nonc\u00e9CorrectionTrier les joueurs du Top14 par taille.
>>> def taillePlayer(player) :\n return int(player['Taille'])\n>>> joueurs_taille_croissant = sorted(joueurs, key = taillePlayer)\n
Exercice 2
\u00c9nonc\u00e9CorrectionTrier les joueurs du Top14 par poids.
>>> def poidsPlayer(player) :\n return int(player['Poids'])\n>>> joueurs_poids_croissant = sorted(joueurs, key = poidsPlayer)\n
Exercice 3
\u00c9nonc\u00e9CorrectionTrier les joueurs de Bordeaux suivant leur Indice de Masse Corporelle (IMC )
>>> def IMC(player):\n masse = int(player['Poids'])\n taille_m = int(player['Taille']) / 100\n return masse / taille_m**2\n>>> joueursUBB = [player for player in joueurs if player['Equipe'] == 'Bordeaux']\n>>> joueursUBB_tri = sorted(joueursUBB, key = IMC)\n
"},{"location":"T5_Traitement_de_donnees/5.2_Trier_des_donnees/cours/#3-recherche-des-joueurs-de-profil-physique-similaire","title":"3. Recherche des joueurs de profil physique similaire","text":""},{"location":"T5_Traitement_de_donnees/5.2_Trier_des_donnees/cours/#31-distance-entre-deux-joueurs","title":"3.1 Distance entre deux joueurs","text":"Construire une fonction distance(joueur1, joueur2)
qui renvoie la somme des carr\u00e9s des diff\u00e9rences de tailles et de poids entre les joueurs joueur1
et joueur2
:
Cette fonction nous permettra d'estimer la diff\u00e9rence morphologique entre deux joueurs.
Utilisation :
>>> distance(joueurs[23], joueurs[31])\n244\n
V\u00e9rification :
>>> joueurs[23]\n{'Equipe': 'Agen', 'Nom': 'Alban CONDUCH\u00c9', 'Poste': 'Centre', 'Date de naissance': '29/10/1996', 'Taille': '190', 'Poids': '102'}\n>>> joueurs[31]\n{'Equipe': 'Agen', 'Nom': 'JJ TAULAGI', 'Poste': 'Arri\u00e8re', 'Date de naissance': '18/06/1993', 'Taille': '180', 'Poids': '90'}\n
\\((102-90)^2+(190-180)^2=244\\)
r\u00e9ponsedef distance(joueur1,joueur2):\n p1 = int(joueur1['Poids'])\n p2 = int(joueur2['Poids'])\n t1 = int(joueur1['Taille'])\n t2 = int(joueur2['Taille'])\n return (p1-p2)**2+(t1-t2)**2\n
"},{"location":"T5_Traitement_de_donnees/5.2_Trier_des_donnees/cours/#32-distance-des-joueurs-avec-baptiste-serin","title":"3.2 Distance des joueurs avec Baptiste Serin","text":"Retrouvons d'abord le num\u00e9ro de Baptiste Serin dans notre classement de joueurs :
>>> for k in range(len(joueurs)) :\n if joueurs[k]['Nom'] == 'Baptiste SERIN' :\n print(k)\n530\n
>>> joueurs[530]\n {'Equipe': 'Toulon',\n 'Nom': 'Baptiste SERIN',\n 'Poste': 'M\u00eal\u00e9e',\n 'Date de naissance': '20/06/1994',\n 'Taille': '180',\n 'Poids': '79'}\n
Baptiste SERIN est donc le joueur num\u00e9ro 530.
Cr\u00e9er une fonction distanceSerin
qui prend en param\u00e8tre un joueur et qui renvoie sa diff\u00e9rence avec Baptiste Serin.
Utilisation :
>>> distanceSerin(joueurs[18])\n745\n
r\u00e9ponse def distanceSerin(joueur):\n return distance(joueurs[530], joueur)\n
Classer l'ensemble des joueurs du Top14 suivant leur diff\u00e9rence morphologique avec Baptiste Serin (du plus proche au plus \u00e9loign\u00e9).
r\u00e9ponse>>> joueurs_VS_Serin = sorted(joueurs, key = distanceSerin)\n>>> joueurs_VS_Serin\n
"},{"location":"T5_Traitement_de_donnees/5.3_Pandas/cours/","title":"5.3 Utilisation du module Pandas","text":""},{"location":"T5_Traitement_de_donnees/5.3_Pandas/cours/#1-introduction-et-premiere-dataframe","title":"1. Introduction et premi\u00e8re dataframe","text":"Le module csv
utilis\u00e9 pr\u00e9c\u00e9demment se contente de lire les donn\u00e9es structur\u00e9es. Il ne fait aucun effort particulier pour analyser les donn\u00e9es. Nous nous en sommes aper\u00e7us lorsqu'il a fallu convertir par int()
toutes les valeurs num\u00e9riques, qui \u00e9taient interpr\u00e9t\u00e9es comme des cha\u00eenes de caract\u00e8res. La biblioth\u00e8que pandas est par contre sp\u00e9cialement con\u00e7ue pour l'analyse des donn\u00e9es (data analysis) : elle est donc naturellement bien plus performante.
Importation du module pandas
L'import se fait classiquement par :
import pandas as pd \n
Le type de variable dans lequel pandas
va stocker les donn\u00e9es s'appelle une dataframe, qui sera souvent abr\u00e9g\u00e9e par df
.
Nous allons retravailler avec le fichier top14.csv
.
Premi\u00e8re dataframe
Nos donn\u00e9es seront ensuite import\u00e9es dans la dataframe df
par l'instruction :
df = pd.read_csv('top14.csv', encoding = 'utf-8') \n
>>> type(df)\n<class 'pandas.core.frame.DataFrame'>\n
"},{"location":"T5_Traitement_de_donnees/5.3_Pandas/cours/#2-observation-des-donnees","title":"2. Observation des donn\u00e9es","text":"Que contient la variable df
?
>>> df\n Equipe Nom Poste Date de naissance Taille Poids\n0 Agen Anton PEIKRISHVILI Pilier 18/09/1987 183 122\n1 Agen Dave RYAN Pilier 21/04/1986 183 116\n2 Agen Giorgi TETRASHVILI Pilier 31/08/1993 177 112\n3 Agen Kamaliele TUFELE Pilier 11/10/1995 182 123\n4 Agen Malino VANA\u00cf Pilier 04/05/1993 183 119\n.. ... ... ... ... ... ...\n590 Toulouse Werner KOK Ailier 27/01/1993 177 78\n591 Toulouse Yoann HUGET Ailier 02/06/1987 190 97\n592 Toulouse Matthis LEBEL Arri\u00e8re 25/03/1999 185 91\n593 Toulouse Maxime M\u00c9DARD Arri\u00e8re 16/11/1986 180 85\n594 Toulouse Thomas RAMOS Arri\u00e8re 23/07/1995 178 86\n\n[595 rows x 6 columns]\n
Les donn\u00e9es sont pr\u00e9sent\u00e9es dans l'ordre originel du fichier.
"},{"location":"T5_Traitement_de_donnees/5.3_Pandas/cours/#21-structure-globale-des-donnees","title":"2.1 Structure globale des donn\u00e9es","text":"La structure des donn\u00e9es : info
>>> df.info()\n<class 'pandas.core.frame.DataFrame'>\nRangeIndex: 595 entries, 0 to 594\nData columns (total 6 columns):\n # Column Non-Null Count Dtype \n--- ------ -------------- ----- \n 0 Equipe 595 non-null object\n 1 Nom 595 non-null object\n 2 Poste 595 non-null object\n 3 Date de naissance 595 non-null object\n 4 Taille 595 non-null int64 \n 5 Poids 595 non-null int64 \ndtypes: int64(2), object(4)\nmemory usage: 28.0+ KB\n
On peut y constater une tr\u00e8s bonne nouvelle : les donn\u00e9es num\u00e9riques sont reconnues comme telles (type int64
).
D'apr\u00e8s la commande pr\u00e9c\u00e9dente, il y a 595 entr\u00e9es dans notre fichier de donn\u00e9es. L'acc\u00e8s \u00e0 une fiche particuli\u00e8re se fera avec la commande loc
.
Acc\u00e8s \u00e0 une fiche : loc
>>> df.loc[312]\nEquipe Lyon\nNom Charlie NGATAI\nPoste Centre\nDate de naissance 17/08/1990\nTaille 188\nPoids 103\nName: 312, dtype: object\n
"},{"location":"T5_Traitement_de_donnees/5.3_Pandas/cours/#23-premieres-et-dernieres-lignes","title":"2.3 Premi\u00e8res et derni\u00e8res lignes","text":"Il est toutefois possible d'avoir uniquement les premi\u00e8res lignes du fichier avec la commande head()
et les derni\u00e8res du fichier avec la commande tail()
. Ces commandes peuvent recevoir en param\u00e8tre un nombre entier :
Les premi\u00e8res lignes du fichier : head
>>> df.head()\n Equipe Nom Poste Date de naissance Taille Poids\n0 Agen Anton PEIKRISHVILI Pilier 18/09/1987 183 122\n1 Agen Dave RYAN Pilier 21/04/1986 183 116\n2 Agen Giorgi TETRASHVILI Pilier 31/08/1993 177 112\n3 Agen Kamaliele TUFELE Pilier 11/10/1995 182 123\n4 Agen Malino VANA\u00cf Pilier 04/05/1993 183 119\n\n>>> df.head(2)\n Equipe Nom Poste Date de naissance Taille Poids\n0 Agen Anton PEIKRISHVILI Pilier 18/09/1987 183 122\n1 Agen Dave RYAN Pilier 21/04/1986 183 116\n
Les derni\u00e8res lignes du fichier : tail
>>> df.tail()\n Equipe Nom Poste Date de naissance Taille Poids\n590 Toulouse Werner KOK Ailier 27/01/1993 177 78\n591 Toulouse Yoann HUGET Ailier 02/06/1987 190 97\n592 Toulouse Matthis LEBEL Arri\u00e8re 25/03/1999 185 91\n593 Toulouse Maxime M\u00c9DARD Arri\u00e8re 16/11/1986 180 85\n594 Toulouse Thomas RAMOS Arri\u00e8re 23/07/1995 178 86\n\n>>> df.tail(3)\n Equipe Nom Poste Date de naissance Taille Poids\n592 Toulouse Matthis LEBEL Arri\u00e8re 25/03/1999 185 91\n593 Toulouse Maxime M\u00c9DARD Arri\u00e8re 16/11/1986 180 85\n594 Toulouse Thomas RAMOS Arri\u00e8re 23/07/1995 178 86\n
"},{"location":"T5_Traitement_de_donnees/5.3_Pandas/cours/#3-analyse-automatique-et-filtrage","title":"3. Analyse automatique et filtrage","text":""},{"location":"T5_Traitement_de_donnees/5.3_Pandas/cours/#31-extraction-dune-colonne","title":"3.1 Extraction d'une colonne","text":"L'id\u00e9e g\u00e9n\u00e9rale est que l'on va cr\u00e9er de nouveaux objets contenant uniquement les renseignements qui nous int\u00e9ressent.
Extraction d'une colonne : df[colonne]
Pour cr\u00e9er une liste contenant uniquement les donn\u00e9es num\u00e9riques de la colonne poids
, il suffit d'\u00e9crire :
poids = df['Poids']\n
La variable poids
est un objet de type Series
(assimilable \u00e0 une liste) qui va pouvoir \u00eatre exploit\u00e9e tr\u00e8s facilement.
On peut d'ailleurs acc\u00e9der \u00e0 un \u00e9l\u00e9ment particulier de cette variable :
>>> poids[15]\n114\n
On confirme donc une excellente nouvelle : les poids sont bien consid\u00e9r\u00e9s nativement comme des nombres. On peut donc se servir de mani\u00e8re tr\u00e8s intuitive de cette fonctionnalit\u00e9 pour faire des graphiques tr\u00e8s facilement, sans conversion comme dans le module csv
!
Pour trouver le poids minimal de cette s\u00e9rie, on utilisera naturellement la fonction min
:
>>> min(poids)\n70\n
Pour tracer notre nuage de points poids-taille, le code sera donc simplement :
import matplotlib.pyplot as plt\nX = df['Poids']\nY = df['Taille']\nplt.plot(X, Y, 'ro')\nplt.show()\n
"},{"location":"T5_Traitement_de_donnees/5.3_Pandas/cours/#32-tri-et-analyse-automatique-des-donnees","title":"3.2 Tri et Analyse automatique des donn\u00e9es","text":"L'interpr\u00e9tation num\u00e9rique permet \u00e0 pandas
d'analyser automatiquement les donn\u00e9es, avec notamment la fonction describe()
.
R\u00e9sum\u00e9 des donn\u00e9es num\u00e9riques : describe
>>> df['Taille'].describe()\ncount 595.000000\nmean 186.559664\nstd 7.572615\nmin 169.000000\n25% 181.000000\n50% 186.000000\n75% 192.000000\nmax 208.000000\nName: Taille, dtype: float64\n
On voit donc que les principaux indicateurs statistiques sont propos\u00e9s.
D'ailleurs, on peut tr\u00e8s facilement tracer des boites \u00e0 moustaches avec la fonction boxplot()
.
graph_taille = df.boxplot(\"Taille\")\ngraph_taille.plot()\nplt.show()\n
Pour les donn\u00e9es non-num\u00e9riques, la commande describe()
n'est que peu d'utilit\u00e9. Elle renseigne toutefois la valeur la plus fr\u00e9quente (en statistiques, le mode ou valeur modale) gr\u00e2ce \u00e0 describe().top
.
Valeur modale de donn\u00e9es non-num\u00e9riques : describe().top
>>> df['Poste'].describe().top\n'3\u00e8me ligne'\n
Pour avoir un d\u00e9tail plus pr\u00e9cis de la r\u00e9partition des donn\u00e9es, on peut utiliser value_counts
:
R\u00e9partition des valeurs : value_counts
>>> df['Poste'].value_counts()\n3\u00e8me ligne 111\nPilier 110\n2\u00e8me ligne 74\nCentre 71\nAilier 64\nTalonneur 50\nM\u00eal\u00e9e 42\nOuverture 38\nArri\u00e8re 35\nName: Poste, dtype: int64\n
Il est possible aussi de trier la dataframe en lui indiquant la colonne de tri :
Trier les donn\u00e9es : sort_values
>>> classement_par_taille = df.sort_values(by='Taille', ascending = True)\n
"},{"location":"T5_Traitement_de_donnees/5.3_Pandas/cours/#4-filtres-et-recherches","title":"4. Filtres et recherches","text":"Le principe du filtrage va \u00eatre de cr\u00e9er une nouvelle dataframe ne contenant que des lignes correspondant \u00e0 un certain crit\u00e8re.
Filtrage des lignes : df[bool\u00e9en]
Comment cr\u00e9er une dataframe ne contenant que les joueurs de l'UBB ? L'id\u00e9e syntaxique est d'\u00e9crire \u00e0 l'int\u00e9rieur de df[]
le test qui permettra le filtrage.
>>> UBB = df[df['Equipe'] == 'Bordeaux']\n
Le bool\u00e9en df['Equipe'] == 'Bordeaux'
doit se comprendre ainsi : on ne veut garder que les joueurs dont le champ Equipe
est \u00e9gal \u00e0 'Bordeaux'
. >>> UBB\n Equipe Nom Poste Date de naissance Taille Poids\n80 Bordeaux Jefferson POIROT Pilier 01/11/1992 181 117\n81 Bordeaux Lasha TABIDZE Pilier 04/07/1997 185 117\n82 Bordeaux Laurent DELBOULB\u00c8S Pilier 17/11/1986 181 106\n83 Bordeaux Lekso KAULASHVILI Pilier 27/08/1992 187 120\n84 Bordeaux Peni RAVAI Pilier 16/06/1990 185 119\n...\n
Exercice 1
Cr\u00e9er une dataframe grands
qui contient tous les joueurs mesurant plus de 2 m\u00e8tres (inclus).
>>> grands = df[df['Taille'] >= 200]\n
Pour effectuer des op\u00e9rations sur les bool\u00e9ens, on utilisera le symbole &
pour le ET et |
pour le OU.
Exercice 2
Cr\u00e9er une dataframe grands_et_gros
qui contient tous les joueurs mesurant plus de 2 m\u00e8tres (inclus) et pesant plus de 120 kg (inclus).
>>> grands_gros = df[(df['Taille'] >= 200) & (df['Poids'] >= 120)]\n
Autre solution, en utilisant la datadframe grands
de l'exercice 1 :
>>> grands_gros = grands[grands['Poids'] >= 120]\n
Exercice 3
Trouver en une seule ligne le joueur le plus l\u00e9ger du Top14.
Correction>>> df[df['Poids'] == min(df['Poids'])]\n Equipe Nom Poste Date de naissance Taille Poids\n491 Racing92 Teddy IRIBAREN M\u00eal\u00e9e 25/09/1990 170 70\n
ou bien
>>> df.sort_values(by='Poids', ascending=True).head(1)\n
Exercice 4
Tracer le nuage de point poids-taille comme pr\u00e9c\u00e9demment, mais en marquant d'un point bleu les 2\u00e8mes ligne et d'un point rouge les piliers.
Correctionimport pandas as pd\nimport matplotlib.pyplot as plt\n\ndf = pd.read_csv('top14.csv', encoding = 'utf-8') \n\nX = df['Poids']\nY = df['Taille']\nplt.plot(X, Y, 'ro')\n\n\nX = df[df['Poste'] == '2\u00e8me ligne']['Poids']\nY = df[df['Poste'] == '2\u00e8me ligne']['Taille']\nplt.plot(X, Y, 'bo')\n\n\nX = df[df['Poste'] == 'Pilier']['Poids']\nY = df[df['Poste'] == 'Pilier']['Taille']\nplt.plot(X, Y, 'go')\n
"},{"location":"T5_Traitement_de_donnees/5.3_Pandas/cours/#5-modification-de-la-structure-rajout-dune-colonne","title":"5. Modification de la structure : rajout d'une colonne","text":"Afin de pouvoir trier les joueurs suivant de nouveaux crit\u00e8res, nous allons rajouter un champ pour chaque joueur. Prenons un exemple stupide : fabriquons un nouveau champ 'Poids apr\u00e8s les vacances'
qui contiendra le poids des joueurs augment\u00e9 de 8 kg. Ceci se fera simplement par :
Rajout d'une colonne
>>> df['Poids apr\u00e8s les vacances'] = df['Poids'] + 8\n
On voit apparaitre dans la dataframe df
une nouvelle colonne
>>> df.head()\n Equipe Nom Poste ... Taille Poids Poids apr\u00e8s les vacances\n0 Agen Anton PEIKRISHVILI Pilier ... 183 122 130\n1 Agen Dave RYAN Pilier ... 183 116 124\n2 Agen Giorgi TETRASHVILI Pilier ... 177 112 120\n3 Agen Kamaliele TUFELE Pilier ... 182 123 131\n4 Agen Malino VANA\u00cf Pilier ... 183 119 127\n\n[5 rows x 7 columns]\n
Pour supprimer cette colonne sans int\u00e9r\u00eat, il suffit de faire :
del df['Poids apr\u00e8s les vacances'] \n
Exercice 5
Q1. Cr\u00e9er une colonne contenant l'IMC de chaque joueur.
Q2. Cr\u00e9er une nouvelle dataframe contenant tous les joueurs du Top14 class\u00e9s par ordre d'IMC croissant.
"},{"location":"T5_Traitement_de_donnees/5.3_Pandas/cours/#6-retour-sur-le-knn","title":"6.\u00a0Retour sur le KNN","text":"Comme dans ce cours, nous allons construire une fonction conseil_poste
recevant en param\u00e8tres :
df
: la dataframe contenant nos donn\u00e9espoids
: le poids du joueur Xtaille
: la taille du joueur Xk
: le nombre de joueurs les plus proches sur lequel on se base pour faire la pr\u00e9dictionqui renvoie le poste le plus compatible avec la morphologie de X.
Il est maintenant possible de coder cette fonction beaucoup plus simplement (mais alors VRAIMENT beaucoup) qu'avec le module csv
.
Il va nous suffir de :
k
premiers \u00e9l\u00e9ments.k
premiers \u00e9lements.Algorithme KNN
import pandas as pd\n\ndf = pd.read_csv('top14.csv', encoding = 'utf-8') \n\ndef conseil_poste(df, poids, taille, k):\n ...\n ...\n ...\n ...\n
>>> conseil_poste(df, 70, 160, 10)\n'M\u00eal\u00e9e'\n>>> conseil_poste(df, 130, 160, 10)\n'Pilier'\n
"},{"location":"T5_Traitement_de_donnees/5.3_Pandas/exercices/","title":"Analyse des passagers du Titanic","text":"Nous allons travailler avec le fichier titanic.csv
.
Dans la barre d'adresse de son navigateur, taper localhost
ou bien 127.0.0.1
.
Si aucune page n'appara\u00eet, c'est que le serveur n'est pas d\u00e9marr\u00e9.
"},{"location":"T6_IHM_Web/pagesperso/#12-demarrer-le-serveur","title":"1.2 D\u00e9marrer le serveur","text":"Dans un terminal, taper
sudo /opt/lampp/lampp start
Dans un terminal,
ip addr
regarder 4 lignes avant la fin, chercher une adresse IP commen\u00e7ant par 192.168.1.XXX
.
Dans un terminal ouvert depuis le dossier contenant ses pages :
sudo cp mapage.html /opt/lampp/htdocs/
Si on veut tout copier :
sudo cp * /opt/lampp/htdocs/
Nous allons tout d'abord consid\u00e9rer le cas o\u00f9 le serveur renvoie une page unique, identique pour tous les utilisateurs. De plus, l'utilisateur ne pourra pas agir sur sa page : il n'y a aucune interactivit\u00e9.
Exemple de page statique c\u00f4t\u00e9 serveur et c\u00f4t\u00e9 utilisateur :
html
pur","text":"Lorsque le client demande au serveur le contenu d'une page web, celui-ci lui renvoie, dans le cas le plus simple, une simple page html
. html
est un langage dit \u00ab \u00e0 balises \u00bb. Ce n'est pas \u00e0 proprement parler un langage de programmation, mais plut\u00f4t un langage de description de contenu. Il a \u00e9t\u00e9 invent\u00e9 en 1992 par Tim Berners-Lee. La version actuellement utilis\u00e9e est le html5
.
Exemple de page web minimale
<!DOCTYPE html>\n<html lang='fr'>\n <head>\n <meta charset=\"utf-8\">\n <title>Un titre tr\u00e8s original</title>\n </head>\n\n <body>\n <p>Ceci est le texte introductif de ma page.</p>\n <p>\n <h1> Ceci est un titre de niveau 1 </h1>\n Mais sans rien d'int\u00e9ressant.\n <h2> Ceci est un titre de niveau 2 </h2>\n <ul>\n <li> le d\u00e9but d'une liste indent\u00e9e </li>\n <li> la suite ... </li>\n </ul> \n Pour apprendre le fonctionnement des balises, voir <a href=\"https://developer.mozilla.org/fr/docs/Apprendre/HTML/Introduction_%C3%A0_HTML/Getting_started\"> ici</a> par exemple !\n </p>\n </body>\n</html>\n
Vous pouvez contempler ici le rendu de cette magnifique page.
Exercice 1
\u00c9nonc\u00e9mapage.html
.html
+ css
","text":"L'acronyme css
signifie Cascading Style Sheets. L'id\u00e9e est de regrouper dans un seul fichier toutes les informations relatives \u00e0 la mise en forme des \u00e9l\u00e9ments de la page html. De mani\u00e8re tr\u00e8s simplifi\u00e9e, on peut dire que le fichier html
s'occupe du fond tandis que le fichier css
s'occupe de la forme.
Le fichier css
(souvent nomm\u00e9 style.css
et appel\u00e9 feuille de style) doit \u00eatre r\u00e9f\u00e9renc\u00e9 au d\u00e9but du fichier html
, au sein de la balise <head>
.
Exemple de couple html
/ css
minimal
fichier index.html
:
<!DOCTYPE html>\n<html>\n <head>\n <meta charset=\"utf-8\">\n <title>page test</title>\n <link href=\"style.css\" rel=\"stylesheet\" type=\"text/css\" />\n </head>\n <body>\n <p>\n <h1> Ceci est un titre de niveau 1 </h1>\n Mais sans rien d'int\u00e9ressant.\n <h2> Ceci est un titre de niveau 2 </h2>\n </p>\n </body>\n</html>\n
fichier style.css
:
html {\nfont-size: 15px;\nfont-family: sans-serif;\nbackground-color: lightgray; }\n\nh1 {\ncolor: red;\n}\n
Vous pouvez contempler ici le nouveau rendu de cette encore plus magnifique page.
En savoir plus
Exercice 2
Reprenez votre page de l'exercice 1 et rajoutez une feuille de style.
Exercice 3
F12
)Jusqu'\u00e0 pr\u00e9sent, la page web envoy\u00e9e par le serveur est :
Le JavaScript va venir r\u00e9gler le probl\u00e8me n\u00b02 : il est possible de fabriquer une page sur laquelle le client va pouvoir agir localement, sans avoir \u00e0 redemander une nouvelle page au serveur.
Invent\u00e9 en 1995 par Brendan Eich pour le navigateur Netscape, le langage JavaScript s'est impos\u00e9 comme la norme aupr\u00e8s de tous les navigateurs pour apporter de l'interactivit\u00e9 aux pages web.
Exemple de couple html
/ javascript
minimal
Notre fichier index.html
fait r\u00e9f\u00e9rence, au sein d'une balise <script>
, \u00e0 un fichier externe script.js
qui contiendra notre code JavaScript.
fichier index.html
:
<!DOCTYPE html>\n<html>\n <head>\n <meta charset=\"utf-8\">\n <title>un peu d'action</title>\n <link href=\"style.css\" rel=\"stylesheet\" type=\"text/css\" />\n </head>\n <body>\n <script src=\"script.js\"></script>\n <p>\n <h2>Une page web extr\u00eamement dynamique</h2>\n </p>\n <div>\n\n <label>Changez la couleur d'arri\u00e8re-plan:</label>\n\n <button type=\"button\" onclick=\"choix('yellow');\">jaune</button>\n\n <button type=\"button\" onclick=\"choix('green');\">vert</button>\n\n <button type=\"button\" onclick=\"choix('purple');\">violet</button> \n </div>\n <div>\n <p>\n En JavaScript, le nom de la couleur choisie est :\n </p>\n <p id=\"resultat\"></p>\n </div>\n </body>\n</html>\n
fichier script.js
:
function choix(color){\ndocument.body.style.background = color;\ndocument.getElementById(\"resultat\").innerHTML=color;\n}\n
Le r\u00e9sultat de cette page peut \u00eatre consult\u00e9 ici. (oui, j'ai confondu le jaune et le rose)
Commentaires
button
, l'attribut onclick
re\u00e7oit le nom d'une fonction d\u00e9clar\u00e9e \u00e0 l'int\u00e9rieur du fichier script.js
, ici la fonction choix()
.La puissance du JavaScript permet de r\u00e9aliser aujourd'hui des interfaces utilisateurs tr\u00e8s complexes au sein d'un navigateur, \u00e9quivalentes \u00e0 celles produites par des logiciels externes (pensez \u00e0 Discord, par ex.). Bien s\u00fbr, dans ces cas complexes, le serveur est aussi sollicit\u00e9 pour modifier la page, comme nous le verrons en partie 3.
En savoir plus
Exercice 4
Rappelons que toutes les pages que nous avons cr\u00e9\u00e9es jusqu'\u00e0 pr\u00e9sent sont uniform\u00e9ment envoy\u00e9es par le serveur au client. Aucune \u00abpr\u00e9paration\u00bb de la page en amont n'a lieu sur le serveur, aucun dialogue n'a lieu avec le serveur une fois que la page a \u00e9t\u00e9 livr\u00e9e. \u00c9videmment, si le web \u00e9tait comme ceci, il ne serait qu'une gigantesque biblioth\u00e8que en consultation seule (ce fut le cas pendant longtemps, et ce qui n'\u00e9tait d\u00e9j\u00e0 pas si mal).
Les langages serveurs, parmi lesquels PHP (pr\u00e9sent sur environ 80% des serveurs), Python (via le framework Django), Java, Ruby, C#, permettent de rajouter de l'interactivit\u00e9 c\u00f4t\u00e9 serveur.
Il convient de rappeler la diff\u00e9rence fondamentale entre une page statique (c\u00f4t\u00e9 serveur) et une page dynamique (c\u00f4t\u00e9 serveur) :
"},{"location":"T6_IHM_Web/6.1_Interactions_page_web/cours/#31-page-statique-cote-serveur","title":"3.1 Page statique (c\u00f4t\u00e9 serveur) :","text":"Lors d'une requ\u00eate d'un client vers un serveur, si le client demande la page index.html
, une copie exacte du fichier index.html
est transmise au client sur sa machine.
Exemple : la page http://glassus1.free.fr/interesting.html que vous avez d\u00e9j\u00e0 consult\u00e9e se trouve telle quelle sur le serveur mis \u00e0 disposition par Free pour l'h\u00e9bergement des pages personnelles :
Depuis votre navigateur, l'affichage du code-source (par Ctrl-U) vous donnera le fichier html tel qu'il \u00e9tait stock\u00e9 sur le serveur.
"},{"location":"T6_IHM_Web/6.1_Interactions_page_web/cours/#32-page-dynamique-cote-serveur","title":"3.2 Page dynamique (c\u00f4t\u00e9 serveur) :","text":"Lors d'une requ\u00eate d'un client vers un serveur, si le client demande la page test.php
, un code html est g\u00e9n\u00e9r\u00e9 \u00e0 partir du fichier test.php
puis est transmise au client sur sa machine. Le fichier transmis ne contient plus de balises php
, il ne comporte que des balises html
classiques.
Exemple : la consultation de la page http://glassus1.free.fr/test.php va renvoyer la page suivante :
dont le code-source est :
Notez bien que ce code-source ne contient que du html
.
Allons regarder cette page du c\u00f4t\u00e9 du serveur :
Le contenu de cette page est :
<!DOCTYPE html>\n<html>\n <head>\n <meta charset=\"utf-8\" />\n <title>Quel jour sommes-nous</title>\n </head>\n <body>\n <p>\n<?php\n $date = date(\"d-m-Y\");\n Print(\"Nous sommes le $date\");\n ?>\n </p>\n</body>\n</html>\n
On y rep\u00e8re la balise <?php>
:
<?php\n $date = date(\"d-m-Y\");\n Print(\"Nous sommes le $date\");\n ?>\n
Ce code php
a donc g\u00e9n\u00e9r\u00e9, lors de l'appel au serveur, le code html
: Nous sommes le 13-04-2020\n
Vous pouvez tester du code PHP et la page g\u00e9n\u00e9r\u00e9e par exemple sur ce site.
Voil\u00e0 comment un serveur peut adapter la page qu'il renvoie, suivant l'utilisateur qui la demande. Nous verrons prochainement comment par des requ\u00eates le client peut envoyer des param\u00e8tres au serveur, et comment celui-ci modifie sa r\u00e9ponse en cons\u00e9quence.
En savoir plus : https://www.php.net/manual/fr/tutorial.firstpage.php
"},{"location":"T6_IHM_Web/6.2_Protocole_HTTP/cours/","title":"6.2 Protocole HTTP : \u00e9tude du chargement d'une page web","text":""},{"location":"T6_IHM_Web/6.2_Protocole_HTTP/cours/#le-protocole-http-des-requetes-et-des-reponses","title":"Le protocole HTTP : des requ\u00eates et des r\u00e9ponses","text":"HTTP (HyperText Transfer Protocol) est le protocole qui r\u00e9git la communication entre :
Prenons pour exemple la requ\u00eate d'un navigateur vers la page http://glassus1.free.fr/interesting.html
interesting.html
, stock\u00e9e sur le serveur glassus1.free.fr
. glassus1.free.fr
(qui est en fait un sous-domaine du serveur des pages personnelles de l'op\u00e9rateur Free). Ici, l'adresse IP sera 212.27.63.111
(on la retrouvera dans la capture de la fen\u00eatre d'Outils de dev\u00e9loppement).212.27.63.111
.Observons \u00e0 partir de l'Inspecteur d'\u00e9l\u00e9ment d'un navigateur (ici Firefox) les informations qui transitent lors de la requ\u00eate et de la r\u00e9ponse.
http://glassus1.free.fr/interesting.html
a g\u00e9n\u00e9r\u00e9 un code de r\u00e9ponse 200 OK, ce qui signifie que la requ\u00eate a \u00e9t\u00e9 trait\u00e9e et que la r\u00e9ponse contenant la page a \u00e9t\u00e9 envoy\u00e9e. Vous pouvez trouver \u00e0 l'adresse https://developer.mozilla.org/fr/docs/Web/HTTP/Status la totalit\u00e9 des codes de r\u00e9ponse possibles. Citons par exemple : http://glassus1.free.fr/interesting.fr
(qui est une page ultra-basique, et n'\u00e9volue pas). Pour r\u00e9-obtenir un code 200, il faut faire un hard-refresh en appuyant sur Maj pendant l'actualisation.HTTP/1.1 200 OK\nDate: Wed, 22 Apr 2020 08:02:01 GMT\nServer: Apache/ProXad [Jan 23 2019 19:58:42]\nLast-Modified: Sun, 12 Apr 2020 16:39:55 GMT\nETag: \"15d7c75-7c-5e93445b\"\nConnection: close\nAccept-Ranges: bytes\nContent-Length: 124\nContent-Type: text/html\n
<!DOCTYPE html>\n<html>\n<head>\n<title>Waouh</title>\n</head>\n<body>\nCeci est vraiment une jolie page web.\n</body>\n</html>\n
Remarque : on peut observer que le navigateur a aussi effectu\u00e9 (de sa propre initiative) une requ\u00eate vers un fichier favicon.ico
qui est l'icone de la page web dans les onglets du navigateur ou la barre de favoris. Ce fichier \u00e9tait bien pr\u00e9sent sur le serveur (ce n'est pas toujours le cas), il a donc \u00e9t\u00e9 envoy\u00e9 dans la r\u00e9ponse du serveur.
De mani\u00e8re g\u00e9n\u00e9rale, une requ\u00eate vers un site web moins \u00e9l\u00e9mentaire va occasionner une multitude de r\u00e9ponses.
Par exemple, l'appel au site www.lyceemauriac.fr
g\u00e9n\u00e8re 129 requ\u00eates/r\u00e9ponses diff\u00e9rentes, compos\u00e9es de fichiers html, css, js, de fichiers de fontes woff2, d'images jpg, png...
Consid\u00e9rons le formulaire suivant, inclus dans une page html ouverte dans le navigateur du client :
Le mot de passe est :\n<form action=\"cible2.php\" method=\"get\">\n<p>\n <input type=\"password\" name=\"pass\" /> \n <input type=\"submit\" value=\"Valider\" />\n</p>\n</form>\n
Aper\u00e7u :
Explications :
cible2.php
est le fichier sur le serveur qui recevra les param\u00e8tres contenus dans le formulaire.pass
et sera de type password
, ce qui signifie qu'on n'affichera pas les caract\u00e8res tap\u00e9s par l'utilisateur. On aurait pu aussi avoir un type :text
: le texte s'affiche en clair (pour les login par ex) radio
: pour une s\u00e9lection (d'un seul \u00e9l\u00e9ment)checkbox
: pour une s\u00e9lection (\u00e9ventuellement multiple)submit
) des param\u00e8tres (ici un seul, la variable pass
) au serveur.Les param\u00e8tres pass\u00e9s au serveur par la m\u00e9thode GET sont transmis dans l'url de la requ\u00eate. Ils sont donc lisibles en clair par n'importe qui.
\u00c9videmment, c'est une m\u00e9thode catastrophique pour la transmission des mots de passe. Par contre, c'est une m\u00e9thode efficace pour acc\u00e9der directement \u00e0 une page particuli\u00e8re : ainsi l'url https://www.google.fr/search?q=bordeaux nous am\u00e8nera directement au r\u00e9sultat de la recherche Google sur le mot-cl\u00e9 \u00abbordeaux\u00bb.
"},{"location":"T6_IHM_Web/6.3_Get_Post_Formulaires/cours/#12-la-methode-post","title":"1.2. La m\u00e9thode POST","text":"Dans notre code de formulaire du 1.1, modifions l'attribut method
, auparavant \u00e9gal \u00e0 \"get\"
. Passons-le \u00e9gal \u00e0 \"post\"
:
Le mot de passe est :\n<form action=\"cible2.php\" method=\"post\">\n<p>\n <input type=\"password\" name=\"pass\" /> \n <input type=\"submit\" value=\"Valider\" />\n</p>\n</form>\n
"},{"location":"T6_IHM_Web/6.3_Get_Post_Formulaires/cours/#test_1","title":"Test :","text":"Les param\u00e8tres pass\u00e9s au serveur par la m\u00e9thode POST ne sont pas visibles dans l'url de la requ\u00eate. Ils sont contenus dans le corps de la requ\u00eate, mais non affich\u00e9s sur le navigateur.
Donc, la transmission du mot de passe est bien s\u00e9curis\u00e9e par la m\u00e9thode POST ?
Pas du tout ! Si le protocole de transmission est du http
et non pas du https
, n'importe qui interceptant le trafic peut lire le contenu de la requ\u00eate et y trouver le mot de passe en clair.
Exemple avec Wireshark :
Le contenu de la variable \"pass\"
est donc visible dans le contenu de la requ\u00eate.
Le passage en https
chiffre le contenu de la requ\u00eate et emp\u00eache donc la simple lecture du mot de passe.
POST : la m\u00e9thode POST doit \u00eatre utilis\u00e9e quand les param\u00e8tres \u00e0 envoyer :
Cette fen\u00eatre est caract\u00e9ristique de l'utilisation d'une m\u00e9thode POST.
Du c\u00f4t\u00e9 du serveur, le langage utilis\u00e9 (PHP, Java...) doit r\u00e9cup\u00e9rer les param\u00e8tres envoy\u00e9s pour modifier les \u00e9lements d'une nouvelle page, mettre \u00e0 jour une base de donn\u00e9es, etc. Comment sont r\u00e9cup\u00e9r\u00e9es ces valeurs ?
"},{"location":"T6_IHM_Web/6.3_Get_Post_Formulaires/cours/#exemple-en-php","title":"Exemple en PHP","text":"L'acronyme PHP signifie **P**HP : **H**ypertext **P**rocessor (c'est un acronyme r\u00e9cursif).
Notre exemple va contenir deux fichiers :
page1.html
, qui contiendra un formulaire et qui renverra, par la m\u00e9thode GET, un param\u00e8tre \u00e0 la page page2.php
.page2.php
, qui g\u00e9n\u00e8rera un code html
personnalis\u00e9 en fonction du param\u00e8tre re\u00e7u. page1.html
","text":"<!DOCTYPE html>\n<html>\n <head>\n <meta charset=\"utf-8\">\n <title>exemple</title>\n </head>\n <body>\n Votre OS actuel est un : \n<form action=page2.php method=\"get\">\n<p>\n <input type=\"radio\" name=\"OS\" value=\"Windows\"> Windows </input>\n <input type=\"radio\" name=\"OS\" value=\"MacOS\"> MacOS </input>\n <input type=\"radio\" name=\"OS\" value=\"GNU/Linux\"> GNU/Linux </input>\n</p>\n<p> \n <input type=\"submit\" value=\"Valider\" />\n</p>\n</form>\n </body>\n</html>\n
"},{"location":"T6_IHM_Web/6.3_Get_Post_Formulaires/cours/#page2php","title":"page2.php
","text":" <!DOCTYPE html>\n<html>\n <head>\n <meta charset=\"utf-8\" />\n <title>Le meilleur OS</title>\n </head>\n <body>\n <p>\n<?php\n if (isset($_GET['OS']))\n {\n Print(\"Vous avez raison, \");\n echo $_GET['OS'];\n Print(\" est le meilleur des OS.\");\n }\n ?>\n </p>\n\n</body>\n</html>\n
"},{"location":"T6_IHM_Web/6.3_Get_Post_Formulaires/cours/#detail-du-fonctionnement","title":"D\u00e9tail du fonctionnement :","text":"page1.html
, un formulaire de type boutons radio lui propose : OS
va recevoir la valeur choisie et va \u00eatre transmise par une requ\u00eate GET \u00e0 l'url donn\u00e9e par la variable action
d\u00e9finie en d\u00e9but de formulaire. Ici, le navigateur va donc demander \u00e0 acc\u00e9der \u00e0 la page page2.php?OS=MacOS
(par exemple)page2.php
va recevoir la demande d'acc\u00e8s \u00e0 la page ainsi que la valeur de la variable OS
. Dans le code PHP, on reconnait :isset($_GET['OS'])
qui v\u00e9rifie si le param\u00e8tre OS
a bien re\u00e7u une valeur.$_GET['OS']
qui r\u00e9cup\u00e8re cette valeur. Si la valeur avait \u00e9t\u00e9 transmise par m\u00e9thode POST (pour un mot de passe, par exemple), la variable aurait \u00e9t\u00e9 r\u00e9cup\u00e9r\u00e9e par $_POST['OS']
. Elle n'aurait par contre pas \u00e9t\u00e9 affich\u00e9e dans l'url de la page.page2.php?OS=MacOS
s'affiche sur le navigateur de l'utilisateur :L'exemple ci-dessus est un mauvais exemple : rien ne justifie l'emploi d'un serveur distant. L'affichage de ce message aurait tr\u00e8s bien pu se faire en local sur le navigateur du client, en Javascript par exemple.
L'envoi de param\u00e8tre \u00e0 un serveur distant est n\u00e9cessaire pour aller interroger une base de donn\u00e9es, par exemple (lorsque vous remplissez un formulaire sur le site de la SNCF, les bases de donn\u00e9es des horaires de trains, des places disponibles et de leurs tarifs ne sont pas h\u00e9berg\u00e9es sur votre ordinateur en local...).
La v\u00e9rification d'un mot de passe doit aussi se faire sur un serveur distant.
"},{"location":"T6_IHM_Web/6.3_Get_Post_Formulaires/cours/#exercice-attaque-par-force-brute-et-requete-get","title":"Exercice : attaque par force brute et requ\u00eate GET","text":""},{"location":"T6_IHM_Web/6.3_Get_Post_Formulaires/cours/#pre-requis-1-le-module-requests-en-python","title":"Pr\u00e9-requis 1 : le modulerequests
en python","text":"Le module requests
permet d'aller chercher le contenu d'une page web, suivant la syntaxe ci-dessous. Testez le code ci-dessous :
import requests\np = requests.get(\"http://glassus1.free.fr/interesting.html\", verify = False)\nprint(p.text)\n
La sortie en console est :
<!DOCTYPE html>\n<html>\n\n<head>\n\n<title>Waouh</title>\n</head>\n\n<body>\nCeci est vraiment une jolie page web.\n</body>\n\n</html>\n
Notre programme Python se comporte donc \u00abcomme un navigateur\u00bb : il se rend sur une page, effectue une requ\u00eate et r\u00e9cup\u00e8re la page renvoy\u00e9e.
"},{"location":"T6_IHM_Web/6.3_Get_Post_Formulaires/cours/#pre-requis-2-lextraction-dun-fichier-texte-sous-forme-de-liste","title":"Pr\u00e9-requis 2 : l'extraction d'un fichier texte sous forme de liste","text":"Le code ci-dessous permet de collecter dans une liste mots
l'ensemble des mots compris dans le fichier monfichiertexte.txt
(si celui-ci comprend un mot par ligne)
mots = open(\"monfichiertexte.txt\").read().splitlines()\n
"},{"location":"T6_IHM_Web/6.3_Get_Post_Formulaires/cours/#exercice","title":"Exercice :","text":"Votre objectif est de trouver le mot de passe demand\u00e9 sur la page http://glassus1.free.fr/exoBF.html
Vous allez vous appuyer sur un leak (fuite) tr\u00e8s c\u00e9l\u00e8bre de mots de passe , qui est le leak du site Rockyou. Dans la base de donn\u00e9es de ce site, 32 millions de mots de passe \u00e9taient stock\u00e9s en clair \u00af\\_(\u30c4)_/\u00af
.
Lorsque le site a \u00e9t\u00e9 pirat\u00e9 (par une injection SQL, voir le cours de Terminale), ces 32 millions de mots de passe se sont retrouv\u00e9s dans la nature. Ils sont aujourd'hui t\u00e9l\u00e9chargeables librement, et constituent un dictionnaire de 14 341 564 mots de passe diff\u00e9rents (car parmi les 32 millions d'utilisateurs, beaucoup utilisaient des mots de passe identiques). Ce fichier est t\u00e9l\u00e9chargeable ici, mais attention il p\u00e8se 134 Mo.
Nous allons utiliser un fichier beaucoup plus l\u00e9ger ne contenant que les 1000 premiers mots de passe : vous le trouverez \u00e0 l'adresse http://glassus1.free.fr/extraitrockyou.txt .
L'un de ces mots de passe est le mot de passe demand\u00e9 \u00e0 la page http://glassus1.free.fr/exoBF.html .
Lequel ?
Correctionimport requests\n\npage_error = requests.get(\"http://glassus1.free.fr/repBF.php?pass=\")\n\nliste_mdp = open(\"extraitrockyou.txt\").read().splitlines()\n\nurl = \"http://glassus1.free.fr/repBF.php?pass=\"\n\nfor mdp in liste_mdp:\n new_url = url + mdp\n print(new_url)\n page_tentative = requests.get(new_url)\n if page_tentative.text != page_error.text:\n print(\"Le mot de passe est le suivant :\", mdp)\n break\n
"},{"location":"T6_Mini-projets/05_Initiation_Pygame/","title":"Initiation \u00e0 Pygame","text":""},{"location":"T6_Mini-projets/05_Initiation_Pygame/#0-preambule","title":"0. Preambule","text":"pip3 install pygame
.Sur votre pc perso, vous pouvez utiliser le gestionnaire de packages de Thonny (Outils / G\u00e9rer les Paquets
)
Installation et param\u00e9trage de Github Desktop
import pygame, sys\nfrom pygame.locals import *\n\npygame.init()\n\nfenetre = pygame.display.set_mode((640, 480))\n\nfenetre.fill([10,186,181])\n\npygame.display.flip()\n\nwhile True :\n pass\n
Ce code devrait vous donner ceci :
Commentaires
sys
permettra de fermer le programme au niveau de l'OS par la commande sys.exit()
from pygame.locals import *
permettra d'utiliser des variables locales d\u00e9j\u00e0 d\u00e9finies par pygame
, comme MOUSEBUTTONDOWN
, par exemple.fenetre
, dans lequel nous viendrons coller de nouveaux \u00e9l\u00e9ments. \u00c9l\u00e9ments structurants d'un code pygame
:
pygame.init()
effectue une initialisation globale de tous les modules pygame
import\u00e9s. \u00c0 mettre au d\u00e9but du code.pygame.display.flip()
effectue un rafra\u00eechissement total de tous les \u00e9l\u00e9ments graphiques de la fen\u00eatre. \u00c0 mettre donc plut\u00f4t vers la fin du code.while True :
comme tr\u00e8s souvent dans les jeux, la structure essentielle est une boucle infinie dont on ne sortira que par une interruption syst\u00e8me (sys.exit()
) o\u00f9 lors de la bascule d'un bool\u00e9en. Pour l'instant, cette boucle est vide (pass
).Nous allons travailler avec le sprite ci-dessous, nomm\u00e9 perso.png
. Il est issu de https://openclassrooms.com/fr/courses/1399541-interface-graphique-pygame-pour-python/1399813-premieres-fenetres
T\u00e9l\u00e9chargez-le pour le mettre dans le m\u00eame dossier que votre code pygame
.
Vous pouvez trouver sur internet un grand nombre de sprites libres de droits, au format png
(donc g\u00e9rant la transparence), dans de multiples positions (ce qui permet de simuler des mouvements fluides). Ici nous travaillerons avec un sprite unique.
perso = pygame.image.load(\"perso.png\").convert_alpha()\n
La fonction convert_alpha()
est appel\u00e9e pour que soit correctement trait\u00e9 le canal de transparence (canal alpha) de notre image."},{"location":"T6_Mini-projets/05_Initiation_Pygame/#23-affichage-de-limage","title":"2.3. Affichage de l'image","text":"\u00c0 ce stade, perso
est un objet pygame
de type Surface
.
Afin de facilement pouvoir le d\u00e9placer, nous allons stocker la position de cet objet dans une variable position_perso
, qui sera de type rect
.
position_perso = perso.get_rect()\n
Pour afficher cette image, nous allons venir le superposer aux \u00e9l\u00e9ments graphiques d\u00e9j\u00e0 dessin\u00e9s (en l'occurence : rien) avec l'instruction blit()
: fenetre.blit(perso, position_perso)\n
\u25b8 r\u00e9capitulatif du code
import pygame, sys\nfrom pygame.locals import *\n\npygame.init()\n\nfenetre = pygame.display.set_mode((640, 480))\nfenetre.fill([10,186,181])\n\nperso = pygame.image.load(\"perso.png\").convert_alpha()\nposition_perso = perso.get_rect()\n\nfenetre.blit(perso, position_perso)\n\npygame.display.flip()\n\nwhile True :\n pass\n
Aper\u00e7u
"},{"location":"T6_Mini-projets/05_Initiation_Pygame/#3-gestion-des-evenements","title":"3. Gestion des \u00e9v\u00e8nements","text":"Lorsqu'un programme pygame
est lanc\u00e9, la variable interne pygame.event.get()
re\u00e7oit en continu les \u00e9v\u00e8nements des p\u00e9riph\u00e9riques g\u00e9r\u00e9s par le syst\u00e8me d'exploitation. Nous allons nous int\u00e9resser aux \u00e9v\u00e8nements de type KEYDOWN
(touche de clavier appuy\u00e9e) ou de type MOUSEBUTTONDOWN
(boutons de souris appuy\u00e9).
La gestion des \u00e9v\u00e8nements nous permettra de pouvoir enfin fermer proprement la fen\u00eatre Pygame, gr\u00e2ce au code suivant :
# routine pour pouvoir fermer \u00abproprement\u00bb la fen\u00eatre Pygame\nfor event in pygame.event.get():\n if event.type == pygame.QUIT:\n pygame.display.quit()\n sys.exit()\n
"},{"location":"T6_Mini-projets/05_Initiation_Pygame/#31-evenements-clavier","title":"3.1. \u00c9v\u00e8nements clavier","text":""},{"location":"T6_Mini-projets/05_Initiation_Pygame/#311-exemple-de-code","title":"3.1.1. Exemple de code","text":"La structure de code pour d\u00e9tecter l'appui sur une touche de clavier est, dans le cas de la d\u00e9tection de la touche \u00abFl\u00e8che droite\u00bb :
for event in pygame.event.get(): \n if event.type == KEYDOWN:\n if event.key == K_RIGHT:\n print(\"fl\u00e8che droite appuy\u00e9e\")\n
La touche (en anglais key) \u00abFl\u00e8che Droite\u00bb est appel\u00e9e K_RIGHT
par pygame
. Le nom de toutes les touches peut \u00eatre retrouv\u00e9 \u00e0 l'adresse https://www.pygame.org/docs/ref/key.html.
Remarque : c'est gr\u00e2ce \u00e0 la ligne initiale
from pygame.locals import *\n
que la variable K_RIGHT
(et toutes les autres) est reconnue."},{"location":"T6_Mini-projets/05_Initiation_Pygame/#312-probleme-de-la-remanence","title":"3.1.2. Probl\u00e8me de la r\u00e9manence","text":"Quand une touche de clavier est appuy\u00e9e, elle le reste un certain temps. Parfois volontairement (sur un intervalle long) quand l'utilisateur d\u00e9cide de la laisser appuy\u00e9e, mais aussi involontairement (sur un intervalle tr\u00e8s court), lors d'un appui \u00abclassique\u00bb. Il existe donc toujours un intervalle de temps pendant lequel la touche reste appuy\u00e9e. Que doit faire notre programme pendant ce temps ? Deux options sont possibles :
Par d\u00e9faut,pygame
est r\u00e9gl\u00e9 sur l'option 1. N\u00e9anmoins, il est classique pour les jeux vid\u00e9os de vouloir que \u00ablaisser la touche appuy\u00e9e\u00bb continue \u00e0 faire avancer le personnage. Nous allons donc faire en sorte que toutes les 50 millisecondes, un nouvel appui soit d\u00e9tect\u00e9 si la touche est rest\u00e9e enfonc\u00e9e. Cela se fera par l'expression :
pygame.key.set_repeat(50)\n
"},{"location":"T6_Mini-projets/05_Initiation_Pygame/#32-evenements-souris","title":"3.2 \u00c9v\u00e8nements souris","text":""},{"location":"T6_Mini-projets/05_Initiation_Pygame/#321-exemple-de-code","title":"3.2.1. Exemple de code","text":"La structure de code pour d\u00e9tecter l'appui sur un bouton de la souris est, dans le cas de la d\u00e9tection du bouton de gauche (le bouton 1) :
for event in pygame.event.get(): \n if event.type == MOUSEBUTTONDOWN and event.button == 1 :\n print(\"clic gauche d\u00e9tect\u00e9\")\n
"},{"location":"T6_Mini-projets/05_Initiation_Pygame/#322-recuperation-des-coordonnees-de-la-souris","title":"3.2.2. R\u00e9cup\u00e9ration des coordonn\u00e9es de la souris","text":"Le tuple (abscisse, ordonn\u00e9e)
des coordonn\u00e9es de la souris sera r\u00e9cup\u00e9r\u00e9 avec l'instruction pygame.mouse.get_pos()
.
Le d\u00e9placement d'un personnage se fera toujours par modification de ses coordonn\u00e9es (et visuellement, par effacement de la derni\u00e8re position). Ce d\u00e9placement pourra \u00eatre :
Pour afficher le personnage \u00e0 la position (100,200)
, on \u00e9crira :
position_perso.topleft = (100,200)\n
o\u00f9 position_perso
est l'objet de type rect
contenant les coordonn\u00e9es. Exercice 1
\u00c9nonc\u00e9Correction possibleR\u00e9aliser un d\u00e9placement al\u00e9atoire, comme l'animation ci-dessous.
Vous pourrez utiliser les instructions :
pygame.time.delay(1000)
afin de ne bouger le personnage que toutes les 1000 millisecondes.randint(a,b)
du package random
, qui renvoie un entier pseudo-al\u00e9atoire entre a
et b
.import pygame, sys\nfrom pygame.locals import *\nfrom random import randint\n\npygame.init()\n\nfenetre = pygame.display.set_mode((640, 480))\n\nperso = pygame.image.load(\"perso.png\").convert_alpha()\n\nposition_perso = perso.get_rect()\n\nwhile True :\n fenetre.fill([10,186,181])\n position_perso.topleft = (randint(0,540),randint(0,380))\n fenetre.blit(perso, position_perso)\n pygame.display.flip()\n pygame.time.delay(1000)\n
"},{"location":"T6_Mini-projets/05_Initiation_Pygame/#42-deplacement-relatif","title":"4.2. D\u00e9placement relatif","text":"Pour d\u00e9placer le personnage de 15 pixels vers la droite et de 10 pixels vers le haut par rapport \u00e0 sa position pr\u00e9c\u00e9dente, on \u00e9crira :
position_perso.move(15,-10)\n
o\u00f9 position_perso
est l'objet de type rect
contenant les coordonn\u00e9es. Exercice 2
\u00c9nonc\u00e9Correction possibleR\u00e9aliser un contr\u00f4le au clavier du personnage, comme dans l'animation ci-dessous.
import pygame, sys\nfrom pygame.locals import *\n\npygame.init()\npygame.key.set_repeat(50)\n\nfenetre = pygame.display.set_mode((640, 480))\n\nperso = pygame.image.load(\"perso.png\").convert_alpha()\n\nposition_perso = perso.get_rect()\n\npas_deplacement = 15 \n\nwhile True :\n\n for event in pygame.event.get() : \n if event.type == KEYDOWN:\n\n if event.key == K_DOWN : \n position_perso = position_perso.move(0,pas_deplacement)\n\n if event.key == K_UP :\n position_perso = position_perso.move(0,-pas_deplacement)\n\n if event.key == K_RIGHT : \n position_perso = position_perso.move(pas_deplacement,0)\n\n if event.key == K_LEFT : \n position_perso = position_perso.move(-pas_deplacement,0) \n\n # routine pour pouvoir fermer \u00abproprement\u00bb la fen\u00eatre Pygame\n if event.type == pygame.QUIT:\n pygame.display.quit()\n sys.exit()\n\n fenetre.fill([10,186,181])\n fenetre.blit(perso, position_perso)\n pygame.display.flip()\n
"},{"location":"T6_Mini-projets/05_Initiation_Pygame/#5-a-vous","title":"5. \u00c0 vous !","text":"Fabriquez le jeu que vous souhaitez \u00e0 partir des informations ci-dessus. Bien d'autres aides peuvent \u00eatre trouv\u00e9es dans les liens cit\u00e9es dans la partie Bibliographie.
Exemple de r\u00e9alisation possible : un clicker avec un temps qui diminue \u00e0 progressivement, et comptage des points.
Quelques aides :
\u00e9crire du texte :
font = pygame.font.Font(pygame.font.get_default_font(), 36)\ntext = font.render(\"Game Over\", True, (255, 0, 0))\nfenetre.blit(text, dest=(550,40))\n
dessiner un rectangle :
pygame.draw.rect(fenetre,(0,255,0),(500,20,100,10))\n
dessine un rectangle vert de 100 pixels sur 10 pixels, dont le coin en haut \u00e0 gauche est \u00e0 la position (500,20). g\u00e9rer le temps:
import time\ntopchrono = time.time()\ndelai = 5\nsortir = False\nwhile sortir == False :\n if time.time() - topchrono > delai :\n print(\"5 secondes se sont \u00e9coul\u00e9es\")\n sortir = True\n
Bibliographie
attention
L'activit\u00e9 ci-dessous n'est pas r\u00e9alisable sous Capytale, qui n'autorise pas l'utilisation du module requests
. Vous devez donc la r\u00e9aliser sur (par exemple) Thonny. Si vous n'avez pas (encore) Thonny sur votre ordinateur personnel, t\u00e9l\u00e9chargez-le ici
Par contre, les r\u00e9ponses aux questions pos\u00e9es doivent \u00eatre donn\u00e9es sur l'activit\u00e9 Capytale https://capytale2.ac-paris.fr/web/c/7371-1140429
Votre objectif est de trouver le mot de passe demand\u00e9 sur la page http://glassus1.free.fr/exoBF.html
Vous allez vous appuyer sur un leak (fuite) tr\u00e8s c\u00e9l\u00e8bre de mots de passe , qui est le leak du site Rockyou. Dans la base de donn\u00e9es de ce site, 32 millions de mots de passe \u00e9taient stock\u00e9s en clair.
Lorsque le site a \u00e9t\u00e9 pirat\u00e9 (par une injection SQL, voir le cours de Terminale), ces 32 millions de mots de passe se sont retrouv\u00e9s dans la nature. Ils sont aujourd'hui t\u00e9l\u00e9chargeables librement, et constituent un dictionnaire de 14 341 564 mots de passe diff\u00e9rents (car parmi les 32 millions d'utilisateurs, beaucoup utilisaient des mots de passe identiques).
Nous allons utiliser un fichier beaucoup plus l\u00e9ger ne contenant que les 1000 premiers mots de passe. Ce fichier est nomm\u00e9 extraitrockyou.txt
.
extraitrockyou.txt
","text":"T\u00e9l\u00e9chargez le fichier extraitrockyou.txt. Attention, ce fichier doit \u00eatre imp\u00e9rativement situ\u00e9 dans le m\u00eame r\u00e9pertoire que le fichier du code Python que vous allez \u00e9crire.
"},{"location":"T6_Mini-projets/Attaque_BF/#12-recuperer-les-elements-du-fichier","title":"1.2 R\u00e9cup\u00e9rer les \u00e9l\u00e9ments du fichier","text":"Ouvrir un nouveau code dans Thonny et enregistrez-le \u00e0 c\u00f4t\u00e9 du fichier extraitrockyou.txt
.
La ligne suivante va stocker dans une liste liste_mdp
les 1000 mots de passe pr\u00e9sents dans le fichier extraitrockyou.txt
.
liste_mdp = open(\"extraitrockyou.txt\").read().splitlines()\n
Si vous avez l'erreur :
FileNotFoundError: [Errno 2] No such file or directory: 'extraitrockyou.txt'\n
c'est que votre code et le fichier extraitrockyou.txt
ne sont pas dans le m\u00eame r\u00e9pertoire.
Question 1
\u00c9crire un code qui affiche les 1000 mots de passe contenus dans liste_mdp
.
(rappel : vous devez aller \u00e9crire vos r\u00e9ponses sur l'activit\u00e9 Capytale https://capytale2.ac-paris.fr/web/c/7371-1140429)
"},{"location":"T6_Mini-projets/Attaque_BF/#2-utilisation-du-module-requests","title":"2. Utilisation du modulerequests
","text":"Le module requests
de Python permet de r\u00e9cup\u00e9rer le contenu d'une page web dont on aura donn\u00e9 l'adresse en param\u00e8tre.
Souvenez-vous par exemple de cette superbe page : http://glassus1.free.fr/interesting.html
Exc\u00e9cutez le code ci-dessous :
import requests\np = requests.get(\"http://glassus1.free.fr/interesting.html\")\nprint(p.text)\n
Question 2
\u00c9crire ce qui s'affiche en console lors de l'ex\u00e9cution du code :
import requests\np = requests.get(\"http://glassus1.free.fr/interesting.html\")\nprint(p.text)\n
Si vous avez l'erreur :
ModuleNotFoundError: No module named 'requests'\n
c'est que le module requests
n'est pas install\u00e9. Dans Thonny, aller dans Outils / G\u00e9rer les paquets et installer requests
.
Un des 1000 mots de passe du fichier extraitrockyou.txt
est le bon. Mais comment savoir lequel ?
Question 3
Rendez-vous sur la page http://glassus1.free.fr/exoBF.html et proposer le mot de passe mauriac
. Quelle url s'affiche alors dans la barre d'adresse ?
Question 4
\u00c9crire un code qui va proposer le mot de passe vacances
et afficher le texte de la page obtenue.
Pour rappel la concat\u00e9nation des chaines de caract\u00e8res permet de faire ceci :
base = \"je vous souhaite de bonnes\"\nsuite = \"vacances\"\nphrase = base + suite\n
Question 5
\u00c9crire un code qui va afficher les 1000 urls diff\u00e9rentes qui serviront \u00e0 tester tous les mots de passe du fichier extraitrockyou.txt
.
Question 6
\u00c9crire un code qui d\u00e9termine le mot de passe de la page http://glassus1.free.fr/exoBF.html.
"},{"location":"T6_Mini-projets/D%C3%A9codeuses/","title":"D\u00e9codeuses du num\u00e9rique","text":"La BD en ligne est disponible ici.
Le pdf est disponible en t\u00e9l\u00e9chargement ici.
Les portraits sont accessibles ici.
Affectation des pr\u00e9sentations
Lors de sa descente vers la plan\u00e8te Mars le 18/02/2021, le rover Perseverance de la Nasa a frein\u00e9 sa chute gr\u00e2ce \u00e0 un parachute qui a intrigu\u00e9 quelques internautes du forum Reddit.
Vid\u00e9o du d\u00e9ploiement du parachute :
Les zones blanches et rouge se d\u00e9composent comme ceci :
"},{"location":"T6_Mini-projets/Exercice_Perseverance/#indications","title":"Indications","text":"Un grand bravo aux brillants redditors u/rdtwt1
et u/tend0g
.
https://sjwarner.github.io/perseverance-parachute-generator/?
"},{"location":"T6_Mini-projets/Exercice_Perseverance/#sources-attention-spoiler","title":"Sources (attention spoiler):","text":"Afin de travailler efficacement entre votre ordinateur personnel et votre VM du lyc\u00e9e, nous utiliser la solution GitHub.
"},{"location":"T6_Mini-projets/Github/#etape-0-creer-un-compte-github","title":"\u00c9tape 0 : cr\u00e9er un compte GitHub","text":"Cela se passe ici
"},{"location":"T6_Mini-projets/Github/#etape-1-creer-un-premier-depot-repository","title":"\u00c9tape 1 : cr\u00e9er un premier d\u00e9p\u00f4t (repository)","text":"Une fois termin\u00e9e la cr\u00e9ation de compte, GitHub vous proposera de cr\u00e9er votre premier d\u00e9p\u00f4t (on dira aussi repository, ou repo). Vous pourrez avoir autant de d\u00e9p\u00f4ts que vous voulez : \u00e0 chaque nouveau projet doit correspondre un nouveau d\u00e9p\u00f4t.
Cr\u00e9ez donc un d\u00e9p\u00f4t Projet Pygame
(ou comme vous voulez).
GitHub Desktop est un logiciel qui devra \u00eatre install\u00e9 sur nos VMs (c'est fait) mais aussi sur votre ordinateur personnel de travail. Vous trouverez les liens de t\u00e9l\u00e9chargement ici.
Le r\u00f4le de GitHub Desktop va \u00eatre de synchroniser vos fichiers locaux avec le serveur distant de github.com (\u00able cloud\u00bb). Contrairement \u00e0 une solution automatique (type Dropbox ou Google Drive), la synchronisation n'est pas automatique mais manuelle. C'est \u00e0 vous d'aller uploader vos fichiers (push) ou bien de les t\u00e9l\u00e9charger (fetch).
"},{"location":"T6_Mini-projets/Github/#etape-3-configurer-github-desktop","title":"\u00c9tape 3 : configurer GitHub Desktop","text":"Il va falloir pr\u00e9ciser \u00e0 GitHub que nous avons d\u00e9j\u00e0 un compte, et un d\u00e9p\u00f4t que nous avons cr\u00e9\u00e9 plus haut. Vous pouvez vous laisser guider ou suivre ce tutoriel
"},{"location":"T7_Divers/1_Conseils_generaux/cours/","title":"Conseils de travail","text":""},{"location":"T7_Divers/1_Conseils_generaux/cours/#conditions-materielles","title":"Conditions mat\u00e9rielles","text":"Il est conseill\u00e9 de travailler avec 3 espaces:
C'est en codant qu'on apprend \u00e0 coder
Tous les exemples de code dans le cours doivent \u00eatre retap\u00e9s (r\u00e9sistez \u00e0 l'envie du copier-coller) dans Thonny, soit en fen\u00eatre de script, soit en console.
Cela permet de :
et le plus important :
Thonny, comme la grande majorit\u00e9 des IDE Python, est compos\u00e9 de deux zones distinctes :
La zone de script est asynchrone. Il ne se passera rien tant que vous n'aurez pas ex\u00e9cut\u00e9 le script (par F5 par exemple). C'est donc l'endroit o\u00f9 on va r\u00e9diger son programme.
La console est synchrone : elle r\u00e9pond d\u00e8s que vous appuyez sur la touche Entr\u00e9e. Elle sert donc aux petits tests rapides, ou bien tests post-ex\u00e9cution d'un code.
Utilisation classique du couple script / console
Pour les extraits de code pr\u00e9sents sur ce site :
Exemple :
def accueil(n):\n for k in range(n):\n print(\"bonjour\") \n
>>>
est \u00e0 taper en console.Exemple :
>>> accueil(5)\n
"},{"location":"T7_Divers/1_Conseils_generaux/cours/#dossiers-fichiers-et-versionning","title":"Dossiers, fichiers et versionning","text":"Cette ann\u00e9e en NSI nous allons manipuler un certain nombre de fichiers. Il est important de les nommer et les classer de fa\u00e7on rigoureuse pour les retrouver rapidement et les partager.
Conseils
python1.py
, python2.py
, python3.py
, etc. Mais plut\u00f4t 1NSI_T4_tri_selection.py
par exemple pour un exercice de programmation sur le tri par selection au th\u00e8me 4.1NSI_projet_morpion_v1.py
, puis 1NSI_projet_morpion_v2.py
, 1NSI_projet_morpion_v3.py
, etc.Utiliser le clavier est souvent bien plus pratique et surtout plus rapide qu'utiliser la souris. Encore faut-il apprendre \u00e0 l'apprivoiser...
La s\u00e9lection au clavier
Outre les touches DEBUT
et FIN
qui permettent d'atteindre rapidement le d\u00e9but ou la fin d'une ligne, les fl\u00e8ches directionelles servent \u00e9videmment \u00e0 se d\u00e9placer dans du texte. Mais combin\u00e9es:
CTRL
: elles permettent de se d\u00e9placer de mot en mot;MAJ
: elles permettent de s\u00e9lectionner un caract\u00e8re;MAJ
et CTRL
: elles permettent de s\u00e9lectionner un mot.De m\u00eame, en se pla\u00e7ant en d\u00e9but d'une ligne et en combinant la touche MAJ
et FIN
, on s\u00e9lectionne la ligne enti\u00e8re.
Les raccourcis clavier
Il existe de tr\u00e8s nombreux raccourcis clavier qui permettent d'ex\u00e9cuter des t\u00e2ches courantes sans passer par les menus du logiciel. Certains sont (quasi-)universels, c'est-\u00e0-dire que ce sont les m\u00eames sur tous les logiciels, d'autres sont sp\u00e9cifiques \u00e0 chaque logiciel. Il est important d'en conna\u00eetre quelques-uns pour \u00eatre plus efficace.
Les universelsIDENavigateur WebCTRL+X
, CTRL+C
, CTRL+V
pour couper, copier, coller;CTRL+O
pour ouvrir un fichierCTRL+N
pour cr\u00e9er un nouveau document;CTRL+S
pour sauvegarder le document en cours;CTRL+MAJ+S
pour sauvegarder en pr\u00e9cisant le nom du fichier;CTRL+Z
pour annuler la derni\u00e8re action, CTRL+Y
ou CTRL+MAJ+Z
pour la r\u00e9tablir;CTRL+W
pour fermer un onglet;CTRL+Q
ou ALT+F4
pour fermer le logiciel;CTRL+A
pour s\u00e9lectionner tout (All).\u00c0 chercher de suite lorsqu'on utilise un nouvel IDE, les raccourcis pour les actions suivantes (entre parenth\u00e8ses ceux de Thonny):
F5
)CTRL+M
)CTRL+T
pour ouvrir un nouvel onglet;CTRL+H
pour ouvrir l'historique;CTRL
+ clic pour forcer l'ouverture d'un lien dans un nouvel onglet;MAJ
+ clic pour forcer l'ouverture d'un lien dans une nouvelle fen\u00eatre;Afin de pouvoir travailler sous le syst\u00e8me d'exploitation libre Linux sur les machines du lyc\u00e9e (sous Windows), nous utilisons la solution de virtualisation Proxmox. De mani\u00e8re simplifi\u00e9e :
Programmation
.Proxmox NSI
. Param\u00e8tres avanc\u00e9s
puis sur Continuer vers le site 172.17.191.244
Proxmox VE Login
, renseigner ses identifiants et s\u00e9lectionner Realm Proxmox VE authentication server
. ok
pour l'ignorer.Start
pour d\u00e9marrer la VM.Console
et choisir Spice
. telechargement.vv
apparu en bas \u00e0 gauche.Remplir ses identifiants dans la fen\u00eatre de connexion :
Basculer l'affichage en plein \u00e9cran
Comme pour tous les langages de programmation, il n'existe pas un logiciel permettant de coder en Python, mais un tr\u00e8s (tr\u00e8s) grand nombre de logiciels diff\u00e9rents, qu'on regroupe sous le nom d'IDE (interfaces de d\u00e9veloppement)
Pour la NSI, nous conseillons Thonny :
"},{"location":"T7_Divers/3_Thonny/cours/#installer-thonny","title":"Installer Thonny","text":"Rendez vous sur la page https://thonny.org/
T\u00e9l\u00e9chargez et installez la version qui correspond \u00e0 votre syst\u00e8me d'exploitation (Windows, Mac, Linux).
Pyzo, PyCharm, Spyder, VisualStudioCode... impossible de toutes les citer !
"},{"location":"T7_Divers/3_Thonny/cours/#solutions-en-ligne","title":"Solutions en ligne","text":"En ligne, sans aucune installation, vous pouvez utiliser https://console.basthon.fr/
ou bien m\u00eame la console ci-dessous !
>>>ou l'IDE qui suit :
\u25b6\ufe0f \u2935\ufe0f \u2934\ufe0f "},{"location":"T7_Divers/4_Processing/cours/","title":"Processing","text":"Processing est un outil de cr\u00e9ation multim\u00e9dia utilisant le code informatique. Simple de prise en main, il a \u00e9t\u00e9 cr\u00e9\u00e9 par des artistes pour des artistes. On peut utiliser le langage Python pour entrer les instructions.
Nous l'utiliserons pour ajouter du graphisme \u00e0 nos cr\u00e9ations...
Documentation"},{"location":"T7_Divers/4_Processing/cours/#les-bases-de-processing","title":"Les bases de Processing","text":""},{"location":"T7_Divers/4_Processing/cours/#repere","title":"Rep\u00e8re","text":"
\u00c0 l'ex\u00e9cution de tout script Processing, une fen\u00eatre s'affiche avec une zone de dessin. Sa taille se d\u00e9finit \u00e0 l'aide de la fonction size
. Par exemple, pour cr\u00e9er une zone de dessin de 300 pixels sur 200 pixels, on utilisera:
size(300, 200)\n
Chaque pixel de cette zone est rep\u00e9r\u00e9e par des coordonn\u00e9es dans le rep\u00e8re suivant, dont l'origine se situe en haut \u00e0 gauche et l'axe des ordonn\u00e9es est orient\u00e9 vers le bas.
"},{"location":"T7_Divers/4_Processing/cours/#traces","title":"Trac\u00e9s","text":"
Trac\u00e9s de base
point
: permet de dessiner un point (pixel). En param\u00e8tre, les coordonn\u00e9es du point.line
: permet de tracer une ligne entre deux points. En param\u00e8tres, les coordonn\u00e9es des deux points.rect
: permet de tracer un rectangle. En param\u00e8tres, les coordonn\u00e9es du sommet haut-gauche, puis la largeur et la hauteur du rectangle.ellipse
: permet de tracer une ellipse. En param\u00e8tres, les coordonn\u00e9es du centre, puis la largeur et la hauteur (mettre la m\u00eame valeur pour un cercle).Copier-coller le code suivant et faire varier les param\u00e8tres pour bien les comprendre.
size(200, 200)\npoint(10, 60)\nline(10, 10, 100, 150)\nrect(80, 10, 20, 50)\nellipse(150, 100, 80, 40)\n
"},{"location":"T7_Divers/4_Processing/cours/#couleurs","title":"Couleurs","text":"Pinceau
background
: permet de d\u00e9finir la couleur du fond de la zone de dessin. En param\u00e8tres, les trois composantes RGB de la couleur.stroke
: permet de d\u00e9finir la couleur du pinceau (noir par d\u00e9faut) pour le contour de la forme. En param\u00e8tres, les trois composantes RGB de la couleur.noStroke
: permet de dessiner une forme sans coutour (pas de param\u00e8tre).strokeWeight
: permet de d\u00e9finir la largeur du pinceau. En param\u00e8tre, le nombre de pixel.fill
: permet de d\u00e9finir la couleur de remplissage de la forme. En param\u00e8tres, les trois composantes RGB de la couleur.Copier-coller le code suivant et faire varier les param\u00e8tres pour bien les comprendre.
size(200, 200)\nbackground(255, 255, 255)\nstroke(255, 0, 0)\npoint(10, 60)\nline(10, 10, 100, 150)\nstroke(0, 127, 255)\nstrokeWeight(5)\nrect(80, 10, 20, 50)\nnoStroke()\nfill(204, 153, 204)\nellipse(150, 100, 80, 40)\n
"},{"location":"T7_Divers/4_Processing/cours/#exercices","title":"Exercices","text":"Exercice 2
\u00c9crire un programme qui affiche le drapeau fran\u00e7ais, comme ci-contre, dans une zone de 300 x 200 pixels.
Exercice 3
\u00c9crire un programme qui trace un quadrillage (espacement de 20 pixels).
Contrainte: en seulement 3 lignes (sans compter \u00e9ventuellement size
.
Exercice 4
Afficher une croix verte de longueur 50 centr\u00e9e au point (60 ; 40), et un cercle rouge de diam\u00e8tre 30 centr\u00e9 en (150 ; 100). On prendra 10 pixels comme \u00e9paisseur.
Exercice 5
Cr\u00e9ez un programme permettant d\u2019afficher 100 disques \u00e0 l\u2019\u00e9cran. La taille de chaque disque devra \u00eatre al\u00e9atoire (mais comprise entre 20 et 50). La couleur de chaque disque devra aussi \u00eatre al\u00e9atoire.
Avec Processing, il est tr\u00e8s simple d\u2019avoir un nombre al\u00e9atoire : random(a,b)
permet d\u2019obtenir un nombre al\u00e9atoire entre a
et b
.
Pour r\u00e9aliser facilement de jolis graphiques, nous utilisons sur les ordinateurs du lyc\u00e9e le logiciel Processing. Celui-ci permet d'\u00e9crire du code Python et d'avoir un rendu imm\u00e9diat dans une fen\u00eatre s\u00e9par\u00e9e.
Pour le travail \u00e0 la maison, nous utilisons le service Capytale.
Probl\u00e8me, il n'est pas possible d'\u00e9crire du code Processing dans Capytale.
"},{"location":"T7_Divers/4_Processing_p5/cours/#2-une-solution-la-librairie-p5","title":"2. Une solution : la librairie p5","text":"Si Processing n'existe pas dans Capytale, une solution tr\u00e8s similaire est disponible : la librairie p5.
Remarque
La librairie p5
incluse dans Capytale est l\u00e9g\u00e8rement diff\u00e9rente de la libraire p5
utilisable dans Thonny (ou tout autre IDE). En effet, pour pouvoir fonctionner sur Capytale, elle a \u00e9t\u00e9 en partie r\u00e9-\u00e9crite par un des d\u00e9veloppeurs de Capytale, Romain Casati.
Les codes Processing que nous avons \u00e9crits jusqu'\u00e0 pr\u00e9sent sont des codes statiques. Mais l'architecture naturelle d'un code Processing ou p5 est en r\u00e9alit\u00e9 articul\u00e9e autour de deux fonctions : la fonction setup()
et la fonction draw()
.
setup()
","text":"Comme son nom l'indique, elle va proc\u00e9der \u00e0 tous les r\u00e9glages initiaux avant de commencer le dessin : taille de la fen\u00eatre, (\u00e9ventuellement couleur d'arri\u00e8re-plan), autres r\u00e9glages.
Elle n'est ex\u00e9cut\u00e9e qu'une seule fois.
"},{"location":"T7_Divers/4_Processing_p5/cours/#32-la-fonction-draw","title":"3.2 La fonctiondraw()
","text":"C'est dans cette fonction que toutes les instructions de dessin seront donn\u00e9es.
Tr\u00e8s important : cette fonction est une boucle infinie. Elle est donc r\u00e9p\u00e9t\u00e9e (\u00e0 une certaine cadence qui est r\u00e9glable) jusqu'\u00e0 ce que (par exemple) l'utilisateur ferme la fen\u00eatre.
Des instructions \u00e9crites dans la fonction setup()
peuvent influer sur cette boucle infinie draw()
: notamment l'instruction noLoop()
qui permet de n'ex\u00e9cuter la fonction draw()
qu'une seule fois.
run()
","text":"Un code p5 devra forc\u00e9ment se terminer par l'instruction run()
createCanvas()
vs size()
","text":"Pour cr\u00e9er une zone de dessin de 300 pixels sur 300 pixels :
size(300,300)
createCanvas(300,300)
Nos premiers codes en Processing actuellement sont statiques : ils n'ont pas d'animation. Processing accepte alors que le code ne comporte ni fonction setup()
ni fonction draw()
.
Par contre, pour faire un code statique en p5, il faudra quand m\u00eame que les fonctions setup()
etdraw()
soient pr\u00e9sentes. On indiquera l'instruction noLoop()
dans le setup()
pour que le draw()
ne soit execut\u00e9 qu'une fois.
Exemple de passage d'un code statique en Processing \u00e0 un code statique en p5 :
Vous pouvez aussi comparer des codes statiques Processing avec leur \u00e9quivalent en p5 dans la feuille d'exercices sur Processing.
"},{"location":"T7_Divers/5_Capytale/cours/","title":"Utilisation du service Capytale","text":"Capytale est accessible via Lyc\u00e9econnect\u00e9, il faut donc avoir ses identifiants Educonnect.
"},{"location":"T7_Divers/5_Capytale/cours/#activite-test","title":"Activit\u00e9-test :","text":"Go !
.Exercice 1
\u00c9nonc\u00e9Correctionp
et de q
soient \u00e9chang\u00e9es :>>> p = 3\n>>> q = 7\n>>>\n>>>\n>>>\n
2. Proposer une autre m\u00e9thode plus rapide \u00e0 \u00e9crire : >>> p = 3\n>>> q = 7\n>>>\n
>>> p = 3\n>>> q = 7\n>>> temp = p\n>>> p = q\n>>> q = temp\n
2.
>>> p = 3\n>>> q = 7\n>>> p, q = q, p\n
Exercice 2
\u00c9nonc\u00e9Correctionscore
soit augment\u00e9e de 20: >>> score = 0\n>>> \n
>>> score = 0\n>>> \n
1.
>>> score = 0\n>>> score = score + 20\n
2. >>> score = 0\n>>> score += 20\n
Exercice 3
\u00c9nonc\u00e9CorrectionJe souhaite coder un jeu. Je vais stocker dans une variable la largeur de l'\u00e9cran (qui vaudra 640 pixels par d\u00e9faut) et dans une autre variable la hauteur de l'\u00e9cran (qui vaudra 400 pixels par d\u00e9faut).
\u00c9crire ce que peuvent \u00eatre les deux premi\u00e8res lignes de mon code :
1 \n2 \n
largeur_ecran = 640\nhauteur_ecran = 400\n
Exercice 4
\u00c9nonc\u00e9CorrectionOn consid\u00e8re le programme suivant :
for lettre in \"LUNDI\":\n print(lettre)\n
\u00c9crire ci-dessous ce qui s'affiche en console lors de l'ex\u00e9cution de ce programme. \n
L\nU\nN\nD\nI\n
Exercice 5
\u00c9nonc\u00e9CorrectionOn consid\u00e8re le programme suivant :
liste_langages = ['Python', 'C++', 'SmallTalk']\nfor langage in liste_langages:\n print(langage, \"est un langage orient\u00e9-objet\")\n
\u00c9crire ci-dessous ce qui s'affiche en console lors de l'ex\u00e9cution de ce programme.
\n
Python est un langage orient\u00e9-objet\nC++ est un langage orient\u00e9-objet\nSmallTalk est un langage orient\u00e9-objet\n
Exercice 6
\u00c9nonc\u00e9CorrectionProposer un code pour \u00e9crire (intelligemment) les lignes suivantes :
Voici le verdict du Choixpeau Magique :\nHarry sera \u00e0 Griffondor\nHermione sera \u00e0 Griffondor\nRon sera \u00e0 Griffondor\n
\n
print('Voici le verdict du Choixpeau Magique :')\npersonnages = ['Harry', 'Hermione', 'Ron']\nfor nom in personnages:\n print(nom, 'sera \u00e0 Griffondor')\n
"},{"location":"T8_DS/DS03/","title":"DS03","text":"correction sur Capytale.
"},{"location":"T8_Liens_utiles/liens/","title":"Liens utiles","text":""},{"location":"T8_Liens_utiles/liens/#a-propos-de-la-specialite-nsi","title":"\u00c0 propos de la sp\u00e9cialit\u00e9 NSI","text":"Quelques sites de challenges/\u00e9nigmes/d\u00e9fis de programmation:
Interstices
Inria
Au cas o\u00f9 vous vous ennuieriez...
Anciens th\u00e8mes trait\u00e9s
if
if
while
for ... in ...
for ... in ...
Consid\u00e9rons la phrase \u00abnous allons stocker le prix du spectacle dans une variable a
, qui vaudra donc au d\u00e9part 32.\u00bb
Il y a plusieurs commentaires \u00e0 faire sur une telle annonce :
a
est particuli\u00e8rement mal choisi, voir D. Bonnes pratiques de nommage)La phrase pr\u00e9c\u00e9dente donnera donc lieu \u00e0 la ligne Python suivante :
>>> a = 32\n
Attention
Le symbole =
ici utilis\u00e9 n'a rien \u00e0 voir avec le symbole = utilis\u00e9 en math\u00e9matique. On dit qu'on a affect\u00e9 \u00e0 a
la valeur 32, et il faut se repr\u00e9senter mentalement cette action par l'\u00e9criture a \u2190 32
.
Comparaison de la syntaxe dans diff\u00e9rents langages
PythonCPHPJavaJavascriptRustGoa = 32\n
int a = 32;\n
$a = 32;\n
int a = 32;\n
var a = 32;\n
let a = 32;\n
a := 32\n
Une fois la valeur 32 stock\u00e9e dans la variable a
, on peut alors utiliser cette variable :
>>> a\n32\n>>> a + 5\n37\n>>> b\nTraceback (most recent call last):\n File \"<pyshell>\", line 1, in <module>\nNameError: name 'b' is not defined\n
Remarquez bien l'erreur lorsqu'on a fait appel \u00e0 une variable b
qui n'avait jamais \u00e9t\u00e9 d\u00e9finie, comme le dit explicitement le message NameError: name 'b' is not defined
En premi\u00e8re intention, il est possible d'expliquer le fonctionnement interne de l'affectation des variables par la m\u00e9taphore des tiroirs :
\u00c9crire l'instruction :
>>> a = 2\n
va provoquer chez l'ordinateur le comportement suivant :
a
? a
.Cette explication est suffisante pour aborder la notion de variable : c'est un mot (ou une lettre) qui va d\u00e9signer une valeur.
Partie difficile (optionnelle)La m\u00e9taphore du tiroir est malheureusement un peu trop simplificatrice.
"},{"location":"T1_Demarrer_en_Python/1.1_Variables/cours/#b2-une-realite-bien-plus-complexe","title":"B.2 Une r\u00e9alit\u00e9 bien plus complexe...","text":""},{"location":"T1_Demarrer_en_Python/1.1_Variables/cours/#b21-la-commande-id-ladresse-du-tiroir","title":"B.2.1 La commandeid()
: l'adresse du tiroir ?","text":"Python poss\u00e8de une fonction qui renvoie l'adresse m\u00e9moire de la variable donn\u00e9e en argument.
>>> b = 7\n>>> id(b)\n9788800\n
Faites le test avec votre propre IDE Python (vous n'obtiendrez pas forc\u00e9ment la m\u00eame valeur d'adresse m\u00e9moire)
"},{"location":"T1_Demarrer_en_Python/1.1_Variables/cours/#b22-cela-se-complique","title":"B.2.2 Cela se complique.","text":"Sans refermer notre IDE, \u00e9crasons la valeur de b
avec une nouvelle valeur :
>>> b = 12\n
et redemandons l'adresse de b
: >>> id(b)\n9788960\n
Tr\u00e8s mauvaise nouvelle : l'adresse de la variable b
a chang\u00e9. Ceci invalide notre m\u00e9taphore du \u00abtiroir\u00bb, une place unique qui serait r\u00e9serv\u00e9e pour y stocker les valeurs successives d'une variable.
La modification de la valeur de b
ne s'est pas faite \u00aben place\u00bb, la variable b
s'est d\u00e9plac\u00e9e : que s'est-il donc pass\u00e9 ?
L'affectation
>>> b = 9\n
ne provoque pas la r\u00e9servation d\u00e9finitive d'un espace-m\u00e9moire pour la variable b
, mais la cr\u00e9ation d'un lien vers un espace-m\u00e9moire qui contient la valeur 9. Ce lien consiste en l'adresse-m\u00e9moire de cette valeur 9. Cette adresse-m\u00e9moire vaut (sur ma configuration personnelle) 9788864
.
>>> id(b)\n9788864\n
Comme le pr\u00e9sente le ruban ci-dessus, Python pr\u00e9-positionne les entiers (de -5 \u00e0 256) sur des petites adresses-m\u00e9moires, car il consid\u00e8re que ces entiers servent souvent, et doivent donc \u00eatre rapidement accessibles.
Si on cr\u00e9\u00e9 une nouvelle variable tokyo
aussi \u00e9gale \u00e0 9, elle va aussi pointer vers la m\u00eame adresse-m\u00e9moire :
>>> tokyo = 9\n>>> id(tokyo)\n9788864\n
Les variables tokyo
et b
renvoient vers la m\u00eame adresse-m\u00e9moire. Affectons maintenant \u00e0 tokyo
la valeur 2020 et observons son adresse-m\u00e9moire :
>>> tokyo = 2020\n>>> id(tokyo)\n139762979309936\n
L'adresse-m\u00e9moire est (bien) plus grande : elle a \u00e9t\u00e9 choisie sur le moment par Python pour y stocker 2020 (car 2020 > 256).
De mani\u00e8re plus surprenante, si on cr\u00e9\u00e9 une nouvelle variable jo
qui vaut aussi 2020, Python va ouvrir une autre adresse-m\u00e9moire pour y stocker 2020, alors qu'il l'a d\u00e9j\u00e0 stock\u00e9e ailleurs :
>>> jo = 2020\n>>> id(jo)\n139762979310064\n
En r\u00e9sum\u00e9, une variable n'est pas le nom d'un tiroir mais plut\u00f4t le nom d'une fl\u00e8che qui pointe vers un espace-m\u00e9moire de l'ordinateur. - La fl\u00e8che peut pointer vers un nouvel espace-m\u00e9moire sans que le nom de la variable change. - Deux variables peuvent pointer vers le m\u00eame espace-m\u00e9moire.
"},{"location":"T1_Demarrer_en_Python/1.1_Variables/cours/#b3-une-histoire-en-2-temps-evaluation-affectation","title":"B.3 Une histoire en 2 temps : \u00e9valuation, affectation","text":"Observons l'instruction
>>> a = 2 + 3\n
"},{"location":"T1_Demarrer_en_Python/1.1_Variables/cours/#b31-etape-1-levaluation","title":"B.3.1 \u00c9tape 1 : l'\u00e9valuation","text":"Python va prendre la partie \u00e0 droite du signe \u00e9gal et va l'\u00e9valuer, ce qui signifie qu'il va essayer de lui donner une valeur. Dans nos exemples, cette valeur sera num\u00e9rique, mais elle peut \u00eatre d'un autre type (voir plus loin)
Ici, Python effectue le calcul 2 + 3 et l'\u00e9value \u00e0 la valeur 5.
"},{"location":"T1_Demarrer_en_Python/1.1_Variables/cours/#b32-etape-2-laffectation","title":"B.3.2 \u00c9tape 2 : l'affectation","text":"Une fois \u00e9valu\u00e9e l'expression \u00e0 droite du signe =, il ne reste plus qu'\u00e0 l'affecter \u00e0 la variable (d\u00e9j\u00e0 existante ou pas) situ\u00e9e \u00e0 gauche du signe =.
Comme expliqu\u00e9 pr\u00e9c\u00e9demment, un \u00ablien\u00bb est fait entre le nom de la variable et l'adresse-m\u00e9moire qui contient la valeur \u00e9valu\u00e9e. a
sera donc li\u00e9 \u00e0 la valeur 5. Plus simplement, on dira que \u00aba
vaut 5\u00bb
\u00abIncr\u00e9menter\u00bb une variable signifie l'augmenter.
Imaginons une variable appel\u00e9e compteur
. Au d\u00e9marrage de notre programme, elle est initialis\u00e9e \u00e0 la valeur 0.
>>> compteur = 0\n
Consid\u00e9rons qu'\u00e0 un moment du programme, cette variable doit \u00eatre modifi\u00e9e, par exemple en lui ajoutant 1.
En Python, cela s'\u00e9crira :
>>> compteur = compteur + 1\n
Observ\u00e9e avec des yeux de math\u00e9maticien, la pr\u00e9c\u00e9dente instruction est une horreur.
Vue avec des yeux d'informaticien, voil\u00e0 comment est interpr\u00e9t\u00e9e la commande
>>> compteur = compteur + 1\n
compteur + 1
.compteur
. Si celle-ci n'existe pas, un message d'erreur est renvoy\u00e9.compteur
.compteur
avec la valeur obtenue au 3. \u00c0 la fin de ces op\u00e9rations, la variable compteur
a bien augment\u00e9 de 1.
Cette proc\u00e9dure d'incr\u00e9mentation est tr\u00e8s tr\u00e8s classique, il faut la ma\u00eetriser parfaitement !
Syntaxe classique et syntaxe Pythonesque
L'incr\u00e9mentation d'une variable compteur
s'\u00e9crira donc en Python :
>>> compteur = compteur + 1\n
Mais il existe aussi une syntaxe particuli\u00e8re, un peu plus courte : >>> compteur += 1\n
Cette syntaxe peut se ranger dans la cat\u00e9gorie des sucres syntaxiques : c'est bien de la conna\u00eetre, c'est amusant de s'en servir, mais son utilisation n'est en rien obligatoire et peut avoir un effet n\u00e9faste, celui d'oublier r\u00e9ellement ce qu'il se passe derri\u00e8re. Exercice 1
\u00c9nonc\u00e9Correction\u00c9crire le code \u00abclassique\u00bb et le code \u00abPythonesque\u00bb pour l'instruction suivante :
On initialise une variable score
\u00e0 100 et on l'augmente de 15.
>>> score = 100\n>>> score = score + 15\n
ou encore >>> score = 100\n>>> score += 15\n
Exercice 2
\u00c9nonc\u00e9Correction\u00c9crire le code \u00abclassique\u00bb et le code \u00abPythonesque\u00bb pour l'instruction suivante :
On initialise une variable cellule
\u00e0 1 et on la multiplie par 2.
>>> cellule = 1\n>>> cellule = cellule * 2\n
ou bien >>> cellule = 1\n>>> cellule *= 2\n
Exercice 3
\u00c9nonc\u00e9Correction\u00c9crire le code \u00abclassique\u00bb et le code \u00abPythonesque\u00bb pour l'instruction suivante.
On initialise une variable capital
\u00e0 1000 et on lui enl\u00e8ve 5%.
>>> capital = 1000\n>>> capital = capital - capital * 5/100\n
ou bien >>> capital = 1000\n>>> capital *= 0.95\n
"},{"location":"T1_Demarrer_en_Python/1.1_Variables/cours/#b33-lechange-de-variables","title":"B.3.3 L'\u00e9change de variables","text":"Apr\u00e8s l'incr\u00e9mentation, une autre technique de base reviendra fr\u00e9quemment dans nos codes : l'\u00e9change de variables.
Imaginons les variables suivantes :
>>> a = 3\n>>> b = 5\n
Le but est d'\u00e9changer les valeurs de a
et de b
. \u25b8 M\u00e9thode na\u00efve
>>> a = b\n>>> b = a\n
Que valent a
et b
maintenant ?
Malheureusement :
>>> a\n5\n>>> b\n5\n>\n
La variable a
a \u00e9t\u00e9 \u00e9cras\u00e9e d\u00e8s qu'on lui a donn\u00e9 la valeur de la variable b
.
Comment la pr\u00e9server ?
La situation est similaire au probl\u00e8me suivant : comment \u00e9changer le contenu de ces deux verres ?
La m\u00e9thode est \u00e9vidente : il nous faut un troisi\u00e8me verre.
Nous allons faire de m\u00eame pour nos variables. Nous allons utiliser une variable temporaire (on parle aussi de variable tampon) pour conserver la m\u00e9moire de la valeur de a
(par exemple) avant que celle-ci ne se fasse \u00e9craser :
>>> a = 3\n>>> b = 5\n>>> temp = a\n>>> a = b\n>>> b = temp\n
Vous pouvez v\u00e9rifier maintenant que les valeurs de a
et de b
ont bien \u00e9t\u00e9 \u00e9chang\u00e9es.
Syntaxe classique et syntaxe Pythonesque
L'\u00e9change de deux variables a
et de b
s'\u00e9crit donc :
>>> temp = a\n>>> a = b\n>>> b = temp\n
Mais il existe aussi une syntaxe particuli\u00e8re \u00e0 Python, bien plus courte : >>> a, b = b, a\n
C'est de nouveau un sucre syntaxique. Cette syntaxe nous dispense de cr\u00e9er nous-m\u00eame une troisi\u00e8me variable. Mais pas de miracle : en interne, Python cr\u00e9e lui-m\u00eame cette variable temporaire. La simultan\u00e9it\u00e9 n'existe pas en informatique. Exercice 4
\u00c9nonc\u00e9CorrectionUne petite erreur s'est gliss\u00e9e \u00e0 Poudlard :
>>> maison_Harry = \"Serpentard\"\n>>> maison_Malfoy = \"Gryffondor\"\n
Corriger cette erreur, de deux mani\u00e8res diff\u00e9rentes. >>> t = maison_Harry\n>>> maison_Harry = maison_Malfoy\n>>> maison_Malfoy = t\n
ou plus rapidement : >>> maison_Harry, maison_Malfoy = maison_Malfoy, maison_Harry\n
"},{"location":"T1_Demarrer_en_Python/1.1_Variables/cours/#c-differents-types-de-variables","title":"C. Diff\u00e9rents types de variables","text":"Pour l'instant, les variables que nous avons manipul\u00e9es contiennent toutes des nombres entiers.
Sauf les maisons de Poudlard, qui sont des mots cha\u00eenes de caract\u00e8res.
Pour diff\u00e9rencier la nature de ce que peut contenir une variable, on parle alors de type de variable.
En voici quelques uns, que nous d\u00e9couvrirons au fil de l'ann\u00e9e :
Types de base
Voici les types Python les plus fr\u00e9quemment utilis\u00e9s cette ann\u00e9e:
Type Python Traduction Exempleint
entier 42
float
flottant (d\u00e9cimal) 3.1416
str
cha\u00eene de caract\u00e8res (string) \"NSI\"
bool
bool\u00e9en (True ou False) True
tuple
p-uplet (255, 127, 0)
list
liste [0, 1, 2, 3, 4, 5]
dict
dictionnaire {'Homer':43, 'Marge':41, 'Bart':12, 'Lisa':10, 'Maggie':4}
function
fonction print
Comment conna\u00eetre le type d'une variable ? Il suffit dans la console d'utiliser la fonction type
.
>>> a = 1\n>>> type(a)\n<class 'int'>\n
"},{"location":"T1_Demarrer_en_Python/1.1_Variables/cours/#c1-python-et-le-typage-dynamique","title":"C.1 Python et le typage dynamique","text":"Jusqu'\u00e0 pr\u00e9sent, nous ne nous sommes pas occup\u00e9s de pr\u00e9ciser \u00e0 Python le type de notre variable.
a = 3\n
Mais dans certains langages, c'est obligatoire. En C par exemple, il faut \u00e9crire :
int a = 3;\n
Cela signifie (pour le langage C) que notre variable a
n'aura pas le droit de contenir autre chose qu'un nombre entier. Si on \u00e9crit ensuite
a = \"test\";\n
Le compilateur C renverra une erreur : on ne peut pas stocker une cha\u00eene de caract\u00e8res dans une variable qu'on a cr\u00e9\u00e9e comme \u00e9tant de type entier.
Et en Python ?
>>> a = 3\n>>> type(a)\n<class 'int'>\n>>> a = \"test\"\n>>> type(a)\n<class 'str'>\n
Python a chang\u00e9 tout seul le type de notre variable, sans intervention. On parle de typage dynamique.
"},{"location":"T1_Demarrer_en_Python/1.1_Variables/cours/#d-bonnes-pratiques-de-nommage","title":"D. Bonnes pratiques de nommage","text":""},{"location":"T1_Demarrer_en_Python/1.1_Variables/cours/#d1-ce-qui-est-autorise-et-ce-qui-ne-lest-pas","title":"D.1 Ce qui est autoris\u00e9 et ce qui ne l'est pas","text":"Pour nommer correctement une variable, il existe des r\u00e8gles \u00e0 respecter.
Les r\u00e8gles
le nom de la variable peut contenir les caract\u00e8res suivants :
le nom de la variable ne doit pas commencer par un chiffre
andas assert break class continue def del elif else except False finally for from global if import in is lambda None not or pass raise return True try while with yield
"},{"location":"T1_Demarrer_en_Python/1.1_Variables/cours/#d2-du-sens-du-sens-du-sens","title":"D.2 Du sens, du sens, du sens","text":"Hormis pour les indices (de boucles, de tableaux...) un nom de variable (dans un programme destin\u00e9 \u00e0 \u00eatre lu, par vous ou quelqu'un d'autre) doit imp\u00e9rativement avoir du sens :
# PAS BIEN\nif d == 1:\n cep += vm\n\n# BIEN\nif date == 1:\n compte_epargne += versement_mensuel\n
R\u00e8gle d'or
On ne donne jamais un nom de variable au hasard, on le choisit pour qu'il soit explicite.
Oui mais pour donner du sens, il faut souvent plusieurs mots... La longueur du nom de la variable (\u00abc'est trop long \u00e0 taper\u00bb) n'est plus un probl\u00e8me depuis que la grande majorit\u00e9 des IDE propose la compl\u00e9tion automatique. Mais comment former ces longs mots ?
"},{"location":"T1_Demarrer_en_Python/1.1_Variables/cours/#d3-syntaxe-des-noms-a-rallonge","title":"D.3 Syntaxe des noms \u00e0 rallonge","text":"Comment accoler des mots
snake_case
: les mots sont s\u00e9par\u00e9s par des underscores. Conseill\u00e9 en Python.camelCase
: les mots sont s\u00e9par\u00e9s par des majuscules mais la 1\u00e8re lettre est minuscule. Conseill\u00e9 en Javascript.PascalCase
: les mots sont s\u00e9par\u00e9s par des majuscules et la 1\u00e8re lettre est majuscule. Conseill\u00e9 en C.kebab-case
: les mots sont s\u00e9par\u00e9s par des tirets courts. Conseill\u00e9 en HTML - CSS. Sans surprise, en Python, nous utiliserons donc le snake_case
.
for ... in ...
","text":""},{"location":"T1_Demarrer_en_Python/1.2_Boucle_for/cours/#1-les-enumerables","title":"1. Les \u00e9num\u00e9rables","text":"En math\u00e9matiques, on dit qu'un ensemble est d\u00e9nombrable lorsqu'on peut associer \u00e0 chaque \u00e9l\u00e9ment de l'ensemble un nombre (traditionnellement 1, 2, 3 ...)
En informatique, il existe un concept similaire qui va d\u00e9signer les objets que l'on peut \u00e9num\u00e9rer, c'est-\u00e0-dire les d\u00e9composer en une succession ordonn\u00e9e d'\u00e9l\u00e9ments. On les appelle les \u00e9num\u00e9rables ou les it\u00e9rables (Python utilise le mot anglais iterable
).
\"NSI\"
(qui est de type String
) est \u00e9num\u00e9rable : on peut la d\u00e9composer en N
, S
, I
.[4, 3, 17]
(qui est de type List
) est \u00e9num\u00e9rable : on peut la d\u00e9composer en 4
, 3
, 17
.5
(qui est de type Int
) n'est PAS \u00e9num\u00e9rable : on ne peut pas la d\u00e9composer. for ... in ...
","text":""},{"location":"T1_Demarrer_en_Python/1.2_Boucle_for/cours/#21-iterer-sur-une-chaine-de-caracteres","title":"2.1 It\u00e9rer sur une cha\u00eene de caract\u00e8res","text":"La principale caract\u00e9ristique d'un ordinateur est d'exceller dans les op\u00e9rations r\u00e9p\u00e9titives.
(je vous laisse retrouver la citation de G\u00e9rard Berry, professeur au Coll\u00e8ge de France, commen\u00e7ant par \u00abl'ordinateur est...\u00bb)
Il existe donc une instruction permettant de faire une (ou plusieurs) action(s) \u00e0 chaque it\u00e9ration sur un \u00e9l\u00e9ment \u00e9num\u00e9rable.
Exemple fondateur n\u00b01
Le programme suivant :
for k in 'NSI':\n print(k)\n
va donner ceci : N\nS\nI\n
Analyse gr\u00e2ce \u00e0 PythonTutor
\u00c9tudions, gr\u00e2ce \u00e0 PythonTutor, le d\u00e9tail de cette ex\u00e9cution.
Cliquez sur Next et observez bien l'\u00e9volution de la variable k
.
La variable k
prend donc successivement toutes les lettre de la cha\u00eene de caract\u00e8re \"NSI\"
.
Pour chaque valeur de k
, la ou les instruction(s) situ\u00e9es de mani\u00e8re indent\u00e9e sous la ligne du for
seront ex\u00e9cut\u00e9es.
Ici, il y a simplement un print(k)
, donc chaque lettre de \"NSI\"
s'affiche l'une apr\u00e8s l'autre.
Exercice 1
\u00c9nonc\u00e9CorrectionQue donne le script suivant ?
for m in 'NASA':\n print(\"bonjour\")\n
bonjour\nbonjour\nbonjour\nbonjour\n
Dans cet exercice, la variable de boucle m
est muette : elle n'appara\u00eet dans les instructions indent\u00e9es sous le for
.
La variable m
prend successivement les valeurs 'N
, 'A'
, 'S'
et 'A'
, mais on ne le voit pas.
Comment \u00e9viter les erreurs classiques
Quand vous \u00e9crivez une boucle for ... in ...
, veillez bien \u00e0 :
for
par les deux points :
for
les instructions qui doivent \u00eatre r\u00e9p\u00e9t\u00e9es. Si l'indentation ne s'est pas faite automatiquement apr\u00e8s appui sur la touche Entr\u00e9e
, c'est que vous avez oubli\u00e9 les :
. Exemple fondateur n\u00b02
Le programme suivant :
for jour in [\"lundi\", \"mardi\", \"mercredi\", \"jeudi\", \"vendredi\"]:\n print(\"je vais au lyc\u00e9e le\", jour)\n
va donner ceci : je vais au lyc\u00e9e le lundi\nje vais au lyc\u00e9e le mardi\nje vais au lyc\u00e9e le mercredi\nje vais au lyc\u00e9e le jeudi\nje vais au lyc\u00e9e le vendredi\n
Analyse gr\u00e2ce \u00e0 PythonTutor
Attention: tr\u00e8s souvent, l'objet \u00e9num\u00e9rable que la boucle va parcourir aura \u00e9t\u00e9 au pr\u00e9alable stock\u00e9 dans une variable :
Exemple fondateur n\u00b03
Le programme pr\u00e9c\u00e9dent est \u00e9quivalent \u00e0 :
semaine = [\"lundi\", \"mardi\", \"mercredi\", \"jeudi\", \"vendredi\"]\nfor jour in semaine:\n print(\"je vais au lyc\u00e9e le\", jour)\n
Notez l'importance d'avoir choisi des noms de variables explicites : ils aident grandement \u00e0 la lisibilit\u00e9 du code.
Trailer : Dans le cours sp\u00e9cifique sur les listes, nous verrons une toute autre mani\u00e8re de parcourir une liste.
"},{"location":"T1_Demarrer_en_Python/1.2_Boucle_for/cours/#3-comment-repeter-n-fois-la-meme-action","title":"3. Comment r\u00e9p\u00e9tern
fois la m\u00eame action ?","text":"Scratch dispose du (tr\u00e8s pratique) bloc suivant :
Comment effectuer la m\u00eame chose en Python ?
Comment r\u00e9p\u00e9ter 10 fois la phrase \"We're up all night to get lucky\"
?
Nous pourrions nous en sortir par
for k in \"blablablab\": #(1) \n print(\"We're up all night to get lucky\")\n
mais il doit clairement y avoir mieux...
Il y a mieux !
L'ensemble range
Le programme suivant :
for i in range(5):\n print(\"We're up all night to get lucky\")\n
va donner ceci : We're up all night to get lucky\nWe're up all night to get lucky\nWe're up all night to get lucky\nWe're up all night to get lucky\nWe're up all night to get lucky\n
L\u00e0 encore, le i
est une variable muette.
Le _
comme variable muette
Lorsque la variable de boucle est muette et ne sert qu'\u00e0 effectuer \\(n\\) fois la m\u00eame action, on utilise souvent le caract\u00e8re _
(appel\u00e9 underscore)comme variable de boucle.
Il faut le comprendre comme un avertissement au lecteur du code : \u00abcette boucle ne sert qu'\u00e0 faire \\(n\\) fois la m\u00eame chose\u00bb
for _ in range(5):\n print(\"Tout \u00e7a est tr\u00e8s r\u00e9p\u00e9titif\")\n
"},{"location":"T1_Demarrer_en_Python/1.2_Boucle_for/cours/#4-tout-sur-le-range","title":"4. Tout sur le range
.","text":""},{"location":"T1_Demarrer_en_Python/1.2_Boucle_for/cours/#41-retour-sur-lexemple-precedent","title":"4.1 Retour sur l'exemple pr\u00e9c\u00e9dent.","text":"Si nous rendions la variable i
moins muette ?
for i in range(5):\n print(i, \"We're up all night to get lucky\")\n
va donner ceci : 0 We're up all night to get lucky\n1 We're up all night to get lucky\n2 We're up all night to get lucky\n3 We're up all night to get lucky\n4 We're up all night to get lucky\n
i
prend donc successivement toutes les valeurs enti\u00e8res entre 0 et 4. Il y en a bien 5."},{"location":"T1_Demarrer_en_Python/1.2_Boucle_for/cours/#42-utilisation-minimale-de-lobjet-range","title":"4.2 Utilisation minimale de l'objet range()
","text":"Syntaxe minimale de range()
Le programme suivant :
for k in range(4):\n print(k)\n
va donner ceci : 0\n1\n2\n3\n
Interpr\u00e9tation : faire parcourir \u00e0 une variable k
l'ensemble range(n)
va faire prendre \u00e0 k
les valeurs 0, 1, 2, ..., n-1. "},{"location":"T1_Demarrer_en_Python/1.2_Boucle_for/cours/#43-utilisation-avancee-de-lobjet-range","title":"4.3 Utilisation avanc\u00e9e de l'objet range()
","text":"Syntaxe compl\u00e8te de range()
Le programme suivant :
for k in range(5, 15, 2):\n print(k)\n
va donner ceci : 5\n7\n9\n11\n13\n
Interpr\u00e9tation : faire parcourir \u00e0 k
l'ensemble range(start, stop, step)
fait : k
\u00e0 la valeur start
,k
de step
en step
tant que k
est strictement inf\u00e9rieur \u00e0 stop
.Remarques :
step
est omis, il vaut 1 par d\u00e9faut.range(5)
n'est pas \u00abtechniquement\u00bb \u00e9gal \u00e0 la liste [0, 1, 2, 3, 4]
, car ce n'est pas un objet de type List
:>>> type(range(5))\n<class 'range'>\n
Si n\u00e9cessaire, on peut le convertir en liste : >>> list(range(5))\n[0, 1, 2, 3, 4]\n
Il faut donc garder en t\u00eate que l'objet renvoy\u00e9 par range()
est un it\u00e9rable assimilable \u00e0 une liste de nombres.
Exercice 2
Faire afficher les s\u00e9ries de nombres suivantes.\n\nOn utilisera la syntaxe ```print(k, end = ' ')``` ) pour afficher les nombres horizontalement.\n\nA. ```0 1 2 3 4 5``` \n??? success \"Correction\"\n ```python linenums='1'\n for k in range(6):\n print(k, end = ' ')\n ```\nB. ```10 11 12 13 14 15 ``` \n??? success \"Correction\"\n ```python linenums='1'\n for k in range(10,16):\n print(k, end = ' ')\n ```\nC. ```3 6 9 12 ``` \n??? success \"Correction\"\n ```python linenums='1'\n for k in range(3,13,3):\n print(k, end = ' ')\n ```\nD. ```10 9 8 7 6 5 4 3 2 1 0 ``` \n??? success \"Correction\"\n ```python linenums='1'\n for k in range(10,-1,-1):\n print(k, end = ' ')\n ```\n
"},{"location":"T1_Demarrer_en_Python/1.2_Boucle_for/cours/#5-une-situation-classique-la-double-boucle","title":"5. Une situation classique : la double boucle","text":"Il est tr\u00e8s souvent utile d'imbriquer une boucle dans une autre, notamment lors du parcours de tous les pixels d'une image. Prenons pour l'instant un exemple num\u00e9rique.
Exemple fondateur
Le programme suivant :
for a in range(1,5):\n for b in range(1,4):\n p = a * b\n print(a, '*', b, '=', p)\n
va donner ceci : 1 * 1 = 1\n1 * 2 = 2\n1 * 3 = 3\n2 * 1 = 2\n2 * 2 = 4\n2 * 3 = 6\n3 * 1 = 3\n3 * 2 = 6\n3 * 3 = 9\n4 * 1 = 4\n4 * 2 = 8\n4 * 3 = 12\n
Analyse gr\u00e2ce \u00e0 PythonTutor
Exercice 3
\u00c9nonc\u00e9Correction\u00c9crire un programme qui affiche :
Papa dit : \u00ab et une cuill\u00e8re pour Riri ! \u00bb\nPapa dit : \u00ab et une cuill\u00e8re pour Fifi ! \u00bb\nPapa dit : \u00ab et une cuill\u00e8re pour Loulou ! \u00bb\nMaman dit : \u00ab et une cuill\u00e8re pour Riri ! \u00bb\nMaman dit : \u00ab et une cuill\u00e8re pour Fifi ! \u00bb\nMaman dit : \u00ab et une cuill\u00e8re pour Loulou ! \u00bb\nMamie dit : \u00ab et une cuill\u00e8re pour Riri ! \u00bb\nMamie dit : \u00ab et une cuill\u00e8re pour Fifi ! \u00bb\nMamie dit : \u00ab et une cuill\u00e8re pour Loulou ! \u00bb\n
for parent in [\"Papa\", \"Maman\", \"Mamie\"]:\n for enfant in [\"Riri\", \"Fifi\", \"Loulou\"]:\n print(parent, \"dit : \u00ab et une cuill\u00e8re pour\", enfant, \"! \u00bb\")\n
Exercice 4
\u00c9nonc\u00e9CorrectionRajouter \u00e0 la phrase pr\u00e9c\u00e9dente le contenu de la cuill\u00e8re (pur\u00e9e puis compote).
Exemple :
Papa dit : \u00ab et une cuill\u00e8re de pur\u00e9e pour Riri ! \u00bb\nPapa dit : \u00ab et une cuill\u00e8re de compote pour Riri ! \u00bb\nPapa dit : \u00ab et une cuill\u00e8re de pur\u00e9e pour Fifi ! \u00bb\nPapa dit : \u00ab et une cuill\u00e8re de compote pour Fifi ! \u00bb\nPapa dit : \u00ab et une cuill\u00e8re de pur\u00e9e pour Loulou ! \u00bb\nPapa dit : \u00ab et une cuill\u00e8re de compote pour Loulou ! \u00bb\nMaman dit : \u00ab et une cuill\u00e8re de pur\u00e9e pour Riri ! \u00bb\nMaman dit : \u00ab et une cuill\u00e8re de compote pour Riri ! \u00bb\n...\n
for parent in [\"Papa\", \"Maman\", \"Mamie\"]:\n for enfant in [\"Riri\", \"Fifi\", \"Loulou\"]:\n for nourriture in [\"pur\u00e9e\", \"compote\"]:\n print(parent, \"dit : \u00ab et une cuill\u00e8re de\", nourriture, \"pour\", enfant, \"! \u00bb\")\n
"},{"location":"T1_Demarrer_en_Python/1.2_Boucle_for/cours/#6-pour-conclure","title":"6. Pour conclure","text":"\u00c0 retenir
for ... in ...
s'utilise lorsque :Les instructions r\u00e9p\u00e9t\u00e9es peuvent - mais ce n'est pas obligatoire - faire appel \u00e0 la variable de boucle, mais il ne faut pas que ces instructions la modifient.
Ne pas oublier les :
et l'indentation !
range(n)
g\u00e9n\u00e8re une s\u00e9quence de n
nombres entiers: on s'en servira d\u00e8s qu'on aura besoin de r\u00e9p\u00e9ter n
fois des instructions.for ... in
","text":"Exercice 1
\u00c9nonc\u00e9CorrectionOn donne une liste d'acteurs :
liste_acteurs = ['Tahar', 'Omar', 'Guillaume', 'Swann', 'Alex', 'Roschdy']\n
Utilisez cette liste pour produire la sortie suivante:
Tahar a eu le C\u00e9sar du meilleur acteur\nOmar a eu le C\u00e9sar du meilleur acteur\nGuillaume a eu le C\u00e9sar du meilleur acteur\nSwann a eu le C\u00e9sar du meilleur acteur\nAlex a eu le C\u00e9sar du meilleur acteur\nRoschdy a eu le C\u00e9sar du meilleur acteur\n
liste_acteurs = ['Tahar', 'Omar', 'Guillaume', 'Swann', 'Alex', 'Roschdy']\n\nfor acteur in liste_acteurs:\n print(acteur, \"a eu le C\u00e9sar du meilleur acteur\")\n
Concat\u00e9nation de caract\u00e8res
Il est possible de coller (le vrai mot est concat\u00e9ner) deux cha\u00eenes de caract\u00e8res par l'op\u00e9rateur +
:
>>> \"a\" + \"b\"\n'ab'\n
Exercice 2
\u00c9nonc\u00e9CorrectionDans l'extrait de code suivant:
chaine
est une variable initialis\u00e9e avec un str
vide : \"\"
;'bravo'
.L'id\u00e9e est d'ajouter une par une les lettres \u00e0 la variable chaine
.
\u00c0 l'ex\u00e9cution, le programme doit afficher uniquement bravo
.
Compl\u00e9ter le code.
chaine = \"\"\nfor ... in ['b', 'r', 'a', 'v', 'o']:\n ...\nprint(chaine)\n
Cette variable chaine
est appel\u00e9e un accumulateur.
chaine = \"\"\nfor lettre in ['b', 'r', 'a', 'v', 'o']:\n chaine += lettre\n\nprint(chaine)\n
Exercice 3
\u00c9nonc\u00e9CorrectionEn Python, la fonction ord
renvoie le code Unicode d'un caract\u00e8re et la fonction chr
le contraire: elle renvoie le caract\u00e8re correspondant \u00e0 un code Unicode.
Par exemple:
>>> ord('a')\n97\n>>> chr(97)\n'a'\n
Voici une liste contenant les codes Unicode des lettres d'un mot secret... \u00c0 vous d'\u00e9crire un programme o\u00f9 en sortie, la variable mot_secret
contiendra la cha\u00eene de caract\u00e8res de ce mot.
mystere = [111, 107, 44, 32, 98, 105, 101, 110, 32, 106, 111, 117, 233]\nmot_secret = \"\"\n
Exercice 4
\u00c9nonc\u00e9CorrectionOn souhaite calculer la somme des 1000 premiers nombres entiers naturels, c'est-\u00e0-dire:
\\(1+2+3+4+5+ \\dots +999+1000\\)
\u00c9crire un programme avec une variable somme
accumulateur (comme \u00e0 l'exercice 3) qui contiendra la valeur souhait\u00e9e en fin de programme.
somme = 0\nfor k in range(1, 1001):\n somme += k\nprint(somme)\n
Exercice 5
\u00c9nonc\u00e9CorrectionCalculer \\(1\\times 2 \\times 3 \\times \\dots 99 \\times 100\\).
produit = 1\nfor k in range(1,101):\n produit = produit * k\nprint(produit) \n
Exercice 6
\u00c9nonc\u00e9CorrectionProposer un code qui \u00e9crit la table de multiplication de 7, de 8 et de 9.
La sortie doit ressembler \u00e0 :
7*1 = 7\n\n7*2 = 14\n\n... \n...\n\n9*9 = 81 \n
for a in range(7, 10):\n for b in range(1, 10):\n print(a, '*', b, '=', a*b)\n
Exercice 7
\u00c9nonc\u00e9CorrectionSur un jeu d'\u00e9checs, les cases sont rep\u00e9r\u00e9es par une lettre (de A jusqu'\u00e0 H) et par un chiffre (de 1 jusqu'\u00e0 8).
Les cases sont donc A1, A2, A3, ..., H7, H8.
Proposer un code qui \u00e9crit toutes les cases possibles.
for lettre in \"ABCDEFGH\":\n for chiffre in \"12345678\":\n case = lettre + chiffre\n print(case)\n
Autre solution utilisant la conversion d'un entier en chaine de caract\u00e8res, gr\u00e2ce \u00e0 la fonction str
:
for lettre in \"ABCDEFGH\":\n for chiffre in range(1, 9):\n case = lettre + str(chiffre)\n print(case)\n
Exercice 8
Travail sur ipythonblocks
:
Exercice \u00e0 faire sur Capytale : https://capytale2.ac-paris.fr/web/c/8869-1863952
Exercice 9
\u00c9nonc\u00e9CorrectionDans ma trousse je dispose de 5 feutres de couleur :
Pour un exercice, je dois colorier 3 pastilles en choissant sans aucune contrainte des couleurs parmi les 5 disponibles. Je peux tout colorier en jaune (JJJ
) ou bien colorier la 1\u00e8re en orange, la 2\u00e8me en bleu, la 3\u00e8me en vert (OBV
)
Faire afficher la totalit\u00e9 des combinaisons possibles.
couleurs = \"JVNBO\"\nfor c1 in couleurs:\n for c2 in couleurs:\n for c3 in couleurs:\n print(c1 + c2 + c3)\n
"},{"location":"T1_Demarrer_en_Python/1.2_Boucle_for/exos_processing/","title":"Exercices sous Processing","text":""},{"location":"T1_Demarrer_en_Python/1.2_Boucle_for/exos_processing/#1-presentation-de-processing","title":"1. Pr\u00e9sentation de Processing","text":"Processing est un outil de cr\u00e9ation multim\u00e9dia utilisant le code informatique. Simple de prise en main, il a \u00e9t\u00e9 cr\u00e9\u00e9 par des artistes pour des artistes. On peut utiliser le langage Python pour entrer les instructions.
Nous l'utiliserons pour ajouter du graphisme \u00e0 nos cr\u00e9ations. Dans tous les exercices de cette page, les dessins r\u00e9alis\u00e9s seront statiques. Nous verrons plus tard comment Processing permet tr\u00e8s facilement de faire des animations.
Documentation"},{"location":"T1_Demarrer_en_Python/1.2_Boucle_for/exos_processing/#2-les-bases-de-processing","title":"2. Les bases de Processing","text":""},{"location":"T1_Demarrer_en_Python/1.2_Boucle_for/exos_processing/#21-repere","title":"2.1 Rep\u00e8re","text":"
\u00c0 l'ex\u00e9cution de tout script Processing, une fen\u00eatre s'affiche avec une zone de dessin. Sa taille se d\u00e9finit \u00e0 l'aide de la fonction size
. Par exemple, pour cr\u00e9er une zone de dessin de 300 pixels sur 200 pixels, on utilisera:
size(300, 200)\n
Chaque pixel de cette zone est rep\u00e9r\u00e9e par des coordonn\u00e9es dans le rep\u00e8re suivant, dont l'origine se situe en haut \u00e0 gauche et l'axe des ordonn\u00e9es est orient\u00e9 vers le bas.
"},{"location":"T1_Demarrer_en_Python/1.2_Boucle_for/exos_processing/#22-traces","title":"2.2 Trac\u00e9s","text":"
Trac\u00e9s de base
point
: permet de dessiner un point (pixel). En param\u00e8tre, les coordonn\u00e9es du point.line
: permet de tracer une ligne entre deux points. En param\u00e8tres, les coordonn\u00e9es des deux points.rect
: permet de tracer un rectangle. En param\u00e8tres, les coordonn\u00e9es du sommet haut-gauche, puis la largeur et la hauteur du rectangle.ellipse
: permet de tracer une ellipse. En param\u00e8tres, les coordonn\u00e9es du centre, puis la largeur et la hauteur (mettre la m\u00eame valeur pour un cercle).Copier-coller le code suivant et faire varier les param\u00e8tres pour bien les comprendre.
size(200, 200)\npoint(10, 60)\nline(10, 10, 100, 150)\nrect(80, 10, 20, 50)\nellipse(150, 100, 80, 40)\n
"},{"location":"T1_Demarrer_en_Python/1.2_Boucle_for/exos_processing/#23-couleurs","title":"2.3 Couleurs","text":"Pinceau
background
: permet de d\u00e9finir la couleur du fond de la zone de dessin. En param\u00e8tres, les trois composantes RGB de la couleur.stroke
: permet de d\u00e9finir la couleur du pinceau (noir par d\u00e9faut) pour le contour de la forme. En param\u00e8tres, les trois composantes RGB de la couleur.noStroke
: permet de dessiner une forme sans coutour (pas de param\u00e8tre).strokeWeight
: permet de d\u00e9finir la largeur du pinceau. En param\u00e8tre, le nombre de pixel.fill
: permet de d\u00e9finir la couleur de remplissage de la forme. En param\u00e8tres, les trois composantes RGB de la couleur.Copier-coller le code suivant et faire varier les param\u00e8tres pour bien les comprendre.
size(200, 200)\nbackground(255, 255, 255)\nstroke(255, 0, 0)\npoint(10, 60)\nline(10, 10, 100, 150)\nstroke(0, 127, 255)\nstrokeWeight(5)\nrect(80, 10, 20, 50)\nnoStroke()\nfill(204, 153, 204)\nellipse(150, 100, 80, 40)\n
"},{"location":"T1_Demarrer_en_Python/1.2_Boucle_for/exos_processing/#3-exercices-sur-la-simple-boucle","title":"3. Exercices sur la simple boucle","text":"Tous les exercices sont \u00e0 faire dans une fen\u00eatre de 300 pixels sur 300 pixels.
Exercice 1
\u00c9nonc\u00e9Correction en ProcessingCorrection en p5L'objectif est d'obtenir dix lignes al\u00e9atoires, de couleur al\u00e9atoire et d'\u00e9paisseur 10.
Aide
random(a,b)
permet d'obtenir un entier pseudo al\u00e9atoire entre a
et b
.size(300,300)\nbackground(0)\nfor k in range(10):\n Ax = random(0,300)\n Ay = random(0,300)\n Bx = random(0,300)\n By = random(0,300)\n strokeWeight(10)\n stroke(random(0,255), random(0,255), random(0,255))\n line(Ax,Ay,Bx,By)\n
from p5 import *\n\ndef setup():\n createCanvas(300, 300)\n noLoop()\n\ndef draw():\n background(0)\n for k in range(10):\n Ax = random(0,300)\n Ay = random(0,300)\n Bx = random(0,300)\n By = random(0,300)\n strokeWeight(10)\n stroke(random(0,255), random(0,255), random(0,255))\n line(Ax,Ay,Bx,By)\n\nrun()\n
Exercice 2 difficile
\u00c9nonc\u00e9Correction en ProcessingCorrection en p5Reprendre l'exercice pr\u00e9c\u00e9dent en faisant en sorte que chaque ligne commence l\u00e0 o\u00f9 une autre s'arr\u00eate (hormis la premi\u00e8re)
size(300,300)\nbackground(0)\nAx = random(0,300)\nAy = random(0,300)\nfor k in range(10):\n Bx = random(0,300)\n By = random(0,300)\n strokeWeight(10)\n stroke(random(0,255), random(0,255), random(0,255))\n line(Ax,Ay,Bx,By)\n Ax = Bx\n Ay = By\n
from p5 import *\n\ndef setup():\n createCanvas(300, 300)\n noLoop()\n\ndef draw():\n background(0)\n Ax = random(0,300)\n Ay = random(0,300)\n for k in range(10):\n Bx = random(0,300)\n By = random(0,300)\n strokeWeight(10)\n stroke(random(0,255), random(0,255), random(0,255))\n line(Ax,Ay,Bx,By)\n Ax = Bx\n Ay = By\n\nrun()\n
Exercice 3
\u00c9nonc\u00e9Correction en ProcessingCorrection en p5Tracer 50 disques de position, diam\u00e8tre, couleur et transparence al\u00e9atoires.
Aide
size(300,300)\nbackground(0)\nfor k in range(50):\n Ax = random(0,300)\n Ay = random(0,300)\n diametre = random(0,50)\n noStroke()\n r = random(0,255)\n g = random(0,255)\n b = random(0,255)\n a = random(0,255)\n fill(r, g, b, a)\n ellipse(Ax,Ay,diametre, diametre)\n
from p5 import *\n\ndef setup():\n createCanvas(300, 300)\n noLoop()\n\ndef draw():\n background(0)\n for k in range(50):\n Ax = random(0,300)\n Ay = random(0,300)\n diametre = random(0,50)\n noStroke()\n r = random(0,255)\n g = random(0,255)\n b = random(0,255)\n a = random(0,255)\n fill(r, g, b, a)\n ellipse(Ax,Ay,diametre, diametre)\n\nrun()\n
Exercice 4 \u00e0 faire sur Capytale : activit\u00e9 55f1-63735
Lire obligatoirement au pr\u00e9alable la page \u00abComment passer d'un code Processing \u00e0 un code p5\u00bb
\u00c9nonc\u00e9Proposer un code r\u00e9alisant la figure suivante. Votre code devra obligatoirement comporter une boucle for
.
La structure de double boucle va permettre (par exemple) de parcourir l'int\u00e9gralit\u00e9 des pixels d'une image.
Exercices \u00e0 faire sur Capytale : activit\u00e9 38d9-68425
Exercice 5
Construire une image o\u00f9 tous les points ont une couleur al\u00e9atoire.
Exercice 6
Construire une image constitu\u00e9e de carr\u00e9s de 20 pixels de cot\u00e9, de couleur al\u00e9atoire. L'image est toujours un carr\u00e9 de c\u00f4t\u00e9 300 pixels.
"},{"location":"T1_Demarrer_en_Python/1.3_Boucle_while/cours/","title":"1.3 Boucle While","text":""},{"location":"T1_Demarrer_en_Python/1.3_Boucle_while/cours/#1-premiers-exemples","title":"1. Premiers exemples","text":"\u00c0 la diff\u00e9rence essentielle des boucles for
, dont on peut savoir \u00e0 l'avance combien de fois elles vont \u00eatre ex\u00e9cut\u00e9es, les boucles while
sont des boucles dont on ne sort que lorsqu'une condition n'est plus satisfaite.
Avec donc le risque de rester infiniment bloqu\u00e9 \u00e0 l'int\u00e9rieur !
Exemple fondateur n\u00b01
Le programme suivant :
a = 0\nwhile a < 3:\n print(\"ok\")\n a = a + 1\nprint(\"fini\")\n
va donner ceci : ok\nok\nok\nfini\n
Analyse gr\u00e2ce \u00e0 PythonTutor
Question
le code ci-dessous va-t-il donner un r\u00e9sultat diff\u00e9rent ?
a = 0\nwhile a < 3:\n a = a + 1\n print(\"ok\")\nprint(\"fini\")\n
R\u00e9sultat du programme \u23ec ok\nok\nok\nfini\n
Conclusion : l'\u00e9valuation de la condition ne se fait pas \u00e0 chaque ligne mais bien au d\u00e9but de chaque tour de boucle. Si la variable qui d\u00e9clenchera la sortie de boucle atteint sa valeur de sortie au milieu des instructions, les lignes restantes sont quand m\u00eame ex\u00e9cut\u00e9es.
"},{"location":"T1_Demarrer_en_Python/1.3_Boucle_while/cours/#2-syntaxe-generale","title":"2. Syntaxe g\u00e9n\u00e9rale","text":"\u00c9criture d'une boucle while
while condition:\n instruction1\n instruction2\n ...\n instructionN\n
"},{"location":"T1_Demarrer_en_Python/1.3_Boucle_while/cours/#21-la-condition","title":"2.1 La condition","text":"La condition
est un bool\u00e9en, c'est-\u00e0-dire une expression que Python \u00e9valuera \u00e0 True
ou \u00e0 False
.
Exemple de bool\u00e9ens r\u00e9sultant d'une \u00e9valuation :
>>> 1 < 3\nTrue\n>>> 5 > 7\nFalse\n>>> a = 10\n>>> a > 8\nTrue\n
Un cours sur les bool\u00e9ens aura lieu ici.
"},{"location":"T1_Demarrer_en_Python/1.3_Boucle_while/cours/#22-les-instructions","title":"2.2 Les instructions","text":"Les instructions instruction1
jusqu'\u00e0 instructionN
sont ex\u00e9cut\u00e9es dans cet ordre \u00e0 chaque tour de boucle.
Attention : ces instructions doivent obligatoirement avoir un impact sur la condition
\u00e9valu\u00e9e apr\u00e8s le while
(dans le cours sur la dichotomie, nous \u00e9voquerons la notion de variant de boucle).
Voir le pi\u00e8ge n\u00b01 ...
"},{"location":"T1_Demarrer_en_Python/1.3_Boucle_while/cours/#3-les-pieges","title":"3. Les pi\u00e8ges ...","text":""},{"location":"T1_Demarrer_en_Python/1.3_Boucle_while/cours/#31-piege-n1-ne-jamais-sortir-de-la-boucle","title":"3.1 pi\u00e8ge n\u00b01 : ne JAMAIS SORTIR de la boucle","text":"Exemple fondateur n\u00b02
Le programme suivant :
a = 0\nwhile a < 3:\n print(\"ok\")\n a = a + 1\n a = a * 0\nprint(\"ce texte ne s'\u00e9crira jamais\")\n
va \u00e9crire une suite infinie de ok
et ne jamais s'arr\u00eater"},{"location":"T1_Demarrer_en_Python/1.3_Boucle_while/cours/#32-piege-n2-ne-jamais-entrer-dans-la-boucle","title":"3.2 pi\u00e8ge n\u00b02 : ne JAMAIS ENTRER dans la boucle","text":"Exemple fondateur n\u00b03
Le programme suivant :
a = 0\nwhile a > 10:\n print(\"ce texte non plus ne s'\u00e9crira jamais\")\n a = a + 1\n\nprint(\"fini\") \n
va \u00e9crire fini
et s'arr\u00eater.
Exercice 1
\u00c9nonc\u00e9CorrectionTrouver le plus petit nombre entier \\(n\\) tel que \\(2^n\\) soit sup\u00e9rieur \u00e0 1 milliard.
n = 1\nwhile 2**n < 10**9:\n n = n + 1\n print(\"trop petit\")\nprint(\"trouv\u00e9 : \",n)\n
"},{"location":"T1_Demarrer_en_Python/1.3_Boucle_while/cours/#4-quelques-remarques","title":"4. Quelques remarques","text":""},{"location":"T1_Demarrer_en_Python/1.3_Boucle_while/cours/#41-lien-entre-while-et-for","title":"4.1 Lien entre while
et for
","text":"La boucle born\u00e9e for
que nous avons \u00e9tudi\u00e9e est tr\u00e8s pratique.
Mais nous pourrions nous en passer : toutes les boucles for
peuvent en fait \u00eatre r\u00e9-\u00e9crites en utilisant while
. (alors que la r\u00e9ciproque est fausse)
Exercice 2
\u00c9nonc\u00e9CorrectionOn consid\u00e8re le code ci-dessous :
for k in range(5):\n print(\"scooby-doo\")\n
R\u00e9-\u00e9crire ce code en utilisant une boucle while
. k = 0\nwhile k < 5:\n print(\"scooby-doo\")\n k = k + 1\n
"},{"location":"T1_Demarrer_en_Python/1.3_Boucle_while/cours/#42-les-boucles-infinies-volontaires","title":"4.2 Les boucles infinies volontaires","text":"La boucle infinie a \u00e9t\u00e9 pr\u00e9sent\u00e9e comme un danger qu'il faut \u00e9viter.
Pourtant, dans quelques situations, il est d'usage d'enfermer volontairement l'utilisateur dans une boucle infinie.
C'est notamment le cas des codes Processing (ou p5) o\u00f9 la fonction draw()
est une boucle infinie dont on ne sort que lorsqu'un \u00e9v\u00e8nement est intercept\u00e9 (par exemple, le clic sur la fermeture de la fen\u00eatre d'affichage).
Observez et ex\u00e9cutez le code suivant :
while True :\n reponse = input(\"tapez sur la lettre S du clavier pour me sortir de cet enfer : \")\n if reponse == 'S' or reponse == 's':\n break\n\nprint(\"merci, j'\u00e9tais bloqu\u00e9 dans une boucle infinie\")\n
while True
est typique des boucles infinies volontaires. On aurait tout aussi bien pu \u00e9crire while 3 > 2
(on rencontre m\u00eame parfois des while 1
)break
qui comme son nom l'indique permet de casser la boucle (cela marche pour while
comme pour for
) et donc d'en sortir. Son emploi est controvers\u00e9 parmi les puristes de la programmation. Nous dirons juste que c'est une instruction bien pratique.Exercice 3
\u00c9nonc\u00e9CorrectionProposer un code qui choisit un nombre al\u00e9atoire entre 1 et 100, puis qui propose en boucle \u00e0 l'utilisateur de le deviner, tant que celui-ci n'a pas trouv\u00e9.
On donnera \u00e0 l'utilisateur des instructions \"trop grand !\" ou \"trop petit !\" pour le guider.
Aides :
int()
permet de convertir une cha\u00eene de caract\u00e8res en nombre. a
pseudo-al\u00e9atoire : from random import randint\na = randint(1,10)\n
from random import randint\n\nmystere = randint(1, 100)\n\nwhile True:\n reponse = int(input('quel est le nombre myst\u00e8re ? '))\n if reponse > mystere:\n print('trop grand !')\n elif reponse < mystere:\n print('trop petit !')\n else:\n print('bravo !')\n break\n
Exercice 4
\u00c9nonc\u00e9CorrectionEn vous basant sur l'exercice pr\u00e9c\u00e9dent, code un programme d'entra\u00eenement aux tables de multiplication de 1 \u00e0 10.
"},{"location":"T1_Demarrer_en_Python/1.4_Instruction_conditionnelle_if/cours/","title":"1.4 Instruction conditionnelle if","text":"L'instruction conditionnelle if
permet de soumettre l'ex\u00e9cution d'instructions \u00e0 une condition donn\u00e9e. Cette condition sera une expression bool\u00e9enne, comme pour la boucle while
.
Dans les exemples ci-dessous, changez la valeur affect\u00e9e \u00e0 la variable age
afin d'observer les modifications de comportement du programme.
Exemple fondateur n\u00b01
L'exemple minimal ci-dessous ne contient que le mot-cl\u00e9 if
.
age = 20\nif age >= 18:\n print(\"Tu as le droit de vote\")\n
Exemple fondateur n\u00b02
La structure qu'on rencontrera le plus souvent est la structure if ... else ...
age = 20\nif age >= 18:\n print(\"Tu as le droit de vote\")\nelse:\n print(\"D\u00e9sol\u00e9, il faudra attendre\", 18 - age, \"ans avant de pouvoir voter\")\n
Syntaxe g\u00e9n\u00e9rale
if expression bool\u00e9enne:\n *instructions \u00e0 effectuer si l'expression est vraie*\nelse:\n *instructions \u00e0 effectuer si l'expression est fausse*\n
"},{"location":"T1_Demarrer_en_Python/1.4_Instruction_conditionnelle_if/cours/#2-levaluation-de-la-condition","title":"2. L'\u00e9valuation de la condition","text":"Comme pour la boucle while
, on dit que l'expression qui suit le if
est \u00e9valu\u00e9e par Python lors de l'ex\u00e9cution du programme.
Cette \u00e9valuation renvoie un bool\u00e9en, True
ou False
.
Les symboles de comparaison (ou d'appartenance) permettant d'\u00e9crire une condition sont :
Op\u00e9rateurs de comparaison
Op\u00e9rateur Signification==
est \u00e9gal \u00e0 !=
est diff\u00e9rent de <
inf\u00e9rieur \u00e0 >
sup\u00e9rieur \u00e0 <=
inf\u00e9rieur ou \u00e9gal \u00e0 >=
sup\u00e9rieur ou \u00e9gal \u00e0 in
appartient \u00e0 not in
n'appartient pas \u00e0 Exemples
>>> a = 2\n\n>>> a == 3\nFalse\n\n>>> a == 2\nTrue\n\n>>> a != 1\nTrue\n\n>>> a > 2\nFalse\n\n>>> a >= 2\nTrue\n\n>>> a <= 2\nTrue\n\n>>> a <= 5\nTrue\n\n>>> 'e' in 'abracadabra'\nFalse\n\n>>> 'b' in 'abracadabra'\nTrue\n\n>>> 'A' not in 'abracadabra'\nTrue\n\n>>> not True\nFalse\n
Comme nous le verrons dans le cours sur les bool\u00e9ens, ces conditions peuvent \u00eatre combin\u00e9es avec (par exemple) les mots-cl\u00e9s and
ou or
:
>>> b = 20\n>>> b > 15 and b < 30\nTrue\n>>> b > 2000 or b < 30\nTrue\n
Exercice
\u00c9nonc\u00e9CorrectionCompter le nombre de voyelles de la phrase 'cet exercice est prodigieusement ennuyeux'
phrase = 'cet exercice est prodigieusement ennuyeux'\nvoyelles = 'aeiouy'\n
phrase = 'cet exercice est prodigieusement ennuyeux'\nvoyelles = 'aeiouy'\n\ncompteur = 0\n\nfor lettre in phrase:\n if lettre in voyelles:\n compteur += 1\n\nprint(compteur)\n
"},{"location":"T1_Demarrer_en_Python/1.4_Instruction_conditionnelle_if/cours/#3-un-test-tres-frequent-le-test-de-divisibilite","title":"3. Un test tr\u00e8s fr\u00e9quent : le test de divisibilit\u00e9","text":"Exemple fondateur n\u00b03
Pour tester si un nombre n
est divisible par un nombre d
, on teste si le reste de la division euclidienne de n
par d
est \u00e9gal \u00e0 0 :
n = 17\nif n % 2 == 0:\n print(n, \"est un nombre pair\")\nelse:\n print(n, \"est un nombre impair\")\n
Exercice
\u00c9nonc\u00e9CorrectionAfficher la liste de tous les nombres entre 1 et 100 qui sont divisibles \u00e0 la fois par 2 et par 7.
for n in range(1,101):\n if n % 2 == 0 and n % 7 == 0:\n print(n)\n
"},{"location":"T1_Demarrer_en_Python/1.4_Instruction_conditionnelle_if/cours/#4-les-cas-multiples-utilisation-de-elif","title":"4. Les cas multiples : utilisation de elif
","text":"Dans les situations o\u00f9 l'on veut effectuer des instructions diff\u00e9rentes selon les diff\u00e9rentes valeurs prises par une variable, on peut imbriquer les instructions if
... else
.
Observer par exemple le code ci-dessous :
moyenne = 13\n\nif moyenne < 8:\n print(\"rat\u00e9\")\nelse:\n if moyenne < 10:\n print(\"rep\u00eachage\")\n else:\n if moyenne < 12:\n print(\"admis\")\n else:\n if moyenne < 14:\n print(\"mention AB\")\n else:\n if moyenne < 16:\n print(\"mention B\")\n else:\n print(\"mention TB\")\n
Mais cela est vite long et peu lisible, et les diff\u00e9rents niveaux d'indentation peuvent devenir pi\u00e9geux.
Il existe alors une instruction qui contracte else
et if
: elif
(sinon si).
Ce code devient alors
moyenne = 7\n\nif moyenne < 8:\n print(\"rat\u00e9\")\nelif moyenne < 10:\n print(\"rep\u00eachage\")\nelif moyenne < 12:\n print(\"admis\")\nelif moyenne < 14:\n print(\"mention AB\")\nelif moyenne < 16:\n print(\"mention B\")\nelse:\n print(\"mention TB\")\n
"},{"location":"T1_Demarrer_en_Python/1.4_Instruction_conditionnelle_if/cours/#4-recreation-a-vous-dobeir","title":"4. R\u00e9cr\u00e9ation : \u00e0 vous d'ob\u00e9ir !","text":"Le site https://compute-it.toxicode.fr/ vous demande d'ex\u00e9cuter mentalement les instructions affich\u00e9es, \u00e0 l'aide des touches directionnelles de votre clavier. Attention, ce site est tr\u00e8s addictif !
"},{"location":"T1_Demarrer_en_Python/1.4_Instruction_conditionnelle_if/exercices/","title":"Exercices","text":"Exercice 1
\u00c9nonc\u00e9Correction\u00c9crire un programme qui demande deux nombres et qui affiche le plus grand des deux.
Aide : pour stocker dans une variable n
un nombre tap\u00e9 au clavier par l'utilisateur, on utilise le code suivant :
n = int(input('Entrez un nombre'))\n
Exemples d'utilisation du programme :
Premier nombre ? 12\nDeuxi\u00e8me nombre ? 45\nle nombre le plus grand est 45\n
Premier nombre ? 17\nDeuxi\u00e8me nombre ? 17\nles deux nombres sont \u00e9gaux\n
n1 = int(input('Premier nombre ?'))\nn2 = int(input('Deuxi\u00e8me nombre ?'))\n\nif n1 > n2:\n print('le nombre le plus grand est', n1)\nelif n2 > n1:\n print('le nombre le plus grand est', n2)\nelse:\n print('les deux nombres sont \u00e9gaux')\n
Exercice 2
\u00c9nonc\u00e9CorrectionLe jeu du FizzBuzz : il s'agit de compter \u00e0 partir de 1 en rempla\u00e7ant certains nombres par Fizz, Buzz ou Fizzbuzz :
\u00c9crire un code qui joue au FizzBuzz jusqu'\u00e0 50.
Exemple d'utilisation du programme :
1\n2\nfizz\n4\nbuzz\nfizz\n7\n8\n...\n
for k in range(1, 20):\n if k % 3 == 0 and k % 5 == 0:\n print('fizzbuzz')\n elif k % 3 == 0:\n print('fizz')\n elif k % 5 == 0:\n print('buzz')\n else:\n print(k)\n
Exercice 3
\u00c9nonc\u00e9CorrectionUne ann\u00e9e est d\u00e9clar\u00e9e bissextile (et compte donc 366 jours au lieu de 365) si elle est :
\u00c9crire un code qui d\u00e9termine si une ann\u00e9e est bissextile ou non.
Explication : la Terre faisant le tour du Soleil en un peu plus que 365 jours, on s'est dit qu'on allait rajouter un jour tous les 4 ans, mais c'\u00e9tait trop, alors on a enlev\u00e9 un jour tous les 100 ans, mais c'\u00e9tait plus assez, alors on a rajout\u00e9 un jour tous les 400 ans, ce qui donne une approximation convenable.
```python linenums='1' annee = int(input(\"ann\u00e9e ? \"))
if annee % 400 == 0: print(annee, 'est bissextile') elif annee % 4 == 0 and annee % 100 != 0: print(annee, 'est bissextile') else: print(annee, \"n'est pas bissextile\")
"},{"location":"T1_Demarrer_en_Python/1.5_Fonctions/cours/","title":"1.5 Fonctions","text":"La notion de fonction est essentielle en programmation. Elle permet de construire des codes modulaires, plus faciles \u00e0 lire et \u00e0 modifier. En Python, une fonction se cr\u00e9e avec le mot-cl\u00e9 def
.
Exemple fondateur n\u00b01
def accueil():\n print(\"bonjour\")\n print(\"comment allez-vous ?\")\n
Lorsque l'interpr\u00e9teur Python parcourt cette fonction, rien ne s'affiche : la fonction est maintenant pr\u00eate \u00e0 \u00eatre appel\u00e9e, mais n'est pas ex\u00e9cut\u00e9e tant que l'utilisateur ne le demande pas explicitement.
Ce sera le cas pour toutes les fonctions : elles doivent \u00eatre appel\u00e9es pour s'ex\u00e9cuter.
>>> accueil()\nbonjour\ncomment allez-vous ?\n
Dans ce cas d'utilisation, la fonction accueil
n'est qu'un raccourci, une factorisation d'un ensemble d'instructions.
Exemple fondateur n\u00b02
def chat_penible(n):\n for k in range(n):\n print(\"meoww\")\n
>>> chat_penible(3)\nmeoww\nmeoww\nmeoww\n
Vocabulaire
n
est appel\u00e9e param\u00e8tre de la fonction chat_penible
.n
\u00e0 la fonction chat_penible
.chat_penible
avec l'argument 3.Remarques :
print()
est une fonction \u00e0 param\u00e8tre, qui affiche dans la console le contenu du param\u00e8tre.Une fonction peut avoir de multiples param\u00e8tres :
Exemple fondateur n\u00b02
def repete(mot, k):\n for i in range(k):\n print(mot)\n
>>> repete(\"NSI\", 3)\nNSI\nNSI\nNSI\n
L'ordre des param\u00e8tres pass\u00e9s est alors important ! Le code ci-dessous est incorrect.
>>> repete(3, \"test\")\n---------------------------------------------------------------------------\n\nTypeError Traceback (most recent call last)\n\n<ipython-input-9-a84914f8a6c6> in <module>()\n----> 1 repete(3, \"test\")\n\n\n<ipython-input-8-7dc8032e3f17> in repete(mot, k)\n 1 def repete(mot, k) :\n----> 2 for i in range(k):\n 3 print(mot)\n 4 \n 5 repete(\"NSI\", 5)\n\n\nTypeError: 'str' object cannot be interpreted as an integer\n
"},{"location":"T1_Demarrer_en_Python/1.5_Fonctions/cours/#3-fonction-avec-parametres-et-avec-valeur-renvoyee","title":"3. Fonction avec param\u00e8tre(s) et avec valeur renvoy\u00e9e","text":"On retrouve ici la notion classique de fonction rencontr\u00e9e en math\u00e9matiques : un proc\u00e9d\u00e9 qui prend un nombre et en renvoie un autre. En informatique, l'objet renvoy\u00e9 ne sera pas forc\u00e9ment un nombre (cela pourra \u00eatre aussi une liste, un tableau, une image...). Le renvoi d'une valeur se fait gr\u00e2ce au mot-cl\u00e9 return
.
Exemple fondateur n\u00b03
La fonction math\u00e9matique \\(f : x \\longmapsto 2x+3\\) se codera par :
def f(x):\n return 2*x + 3\n
>>> f(10)\n23\n
"},{"location":"T1_Demarrer_en_Python/1.5_Fonctions/cours/#4-autour-du-return","title":"4. Autour du return
","text":""},{"location":"T1_Demarrer_en_Python/1.5_Fonctions/cours/#41-la-force-du-return","title":"4.1 La force du return
","text":"Diff\u00e9rence fondamentale entre return
et print
Le mot-cl\u00e9 return
de l'exemple pr\u00e9c\u00e9dent fait que l'expression f(10)
est \u00e9gale \u00e0 23. On peut d'ailleurs \u00e9crire en console :
>>> f(10) + 5\n28\n
Imaginons (avant de l'oublier tr\u00e8s vite) le code affreux ci-dessous : def g(x):\n print(2*x + 3)\n
On pourrait avoir l'illusion que la fonction g
fait correctement son travail : >>> g(10)\n23\n
Mais g
se contente d'afficher sa valeur calcul\u00e9e, et non pas de la renvoyer. En effet : >>> g(10) + 5\n23\nTraceback (most recent call last):\nFile \"<pyshell>\", line 1, in <module>\nTypeError: unsupported operand type(s) for +: 'NoneType' and 'int'\n
En r\u00e9sum\u00e9 : "},{"location":"T1_Demarrer_en_Python/1.5_Fonctions/cours/#42-le-return-est-un-siege-ejectable","title":"4.2 Le return
est un si\u00e8ge \u00e9jectable","text":"Le mot-cl\u00e9 return
provoque une \u00e9jection du code : tout ce qui est situ\u00e9 apr\u00e8s le \u00a0return
ne sera pas ex\u00e9cut\u00e9. Observez la diff\u00e9rence entre les fonctions g
et h
.
def g(x):\n print(\"ce texte sera bien affich\u00e9\")\n return 2*x+3\n
>>> g(4)\nce texte sera bien affich\u00e9\n11\n
def h(x):\n return 2*x+3\n print(\"ceci ne sera jamais affich\u00e9\")\n
>>> h(4)\n11\n
"},{"location":"T1_Demarrer_en_Python/1.5_Fonctions/cours/#43-les-fonctions-sans-return-sont-elles-des-fonctions","title":"4.3 Les fonctions sans return
sont-elles des fonctions ?","text":"Pour les puristes, une fonction sans valeur renvoy\u00e9e sera plut\u00f4t appel\u00e9e proc\u00e9dure. Le mot fonction est alors r\u00e9serv\u00e9 aux fonctions qui ont effectivement un return
.
On peut doter artificiellement \u00e0 toutes les fonctions d'un return
, en renvoyant la valeur None
:
def chat_penible(n):\n for k in range(n):\n print(\"meoww\")\n return None\n
D\u00e9finitions
On dit que les fonctions cr\u00e9ent leur \u00abespace de noms\u00bb (espace est \u00e0 prendre au sens d'univers), un espace qui leur est propre.
Quelles sont les r\u00e8gles r\u00e9gissant ces espaces de noms ? Les fronti\u00e8res entre ces espaces sont elles poreuses ?
"},{"location":"T1_Demarrer_en_Python/1.5_Fonctions/cours/#52-regles-dacces-en-lecture-et-en-modification-dune-variable-suivant-son-espace-dorigine","title":"5.2 R\u00e8gles d'acc\u00e8s en lecture et en modification d'une variable suivant son espace d'origine","text":"R\u00e8gles d'acc\u00e8s aux variables locales et globales
Exercice
\u00c9nonc\u00e9Correction code ACorrection code BCorrection code COn consid\u00e8re les 3 codes ci-dessous. Pour chacun, dire sans l'ex\u00e9cuter s'il est valide ou non. S'il ne l'est pas, identifier la r\u00e8gle (parmi celles \u00e9nonc\u00e9es ci-dessus) qui est bafou\u00e9e.
code A
points = 0\ndef verdict(reponse):\n if reponse > 10:\n points += 3\n\nverdict(12)\n
code B
def bouge(x, decalage):\n x += decalage\n\nbouge(100, 5)\nprint(x)\n
code C
def test_bac(moyenne):\n if moyenne >= 10:\n print(\"admis !\")\n\ndef coup_de_pouce(note):\n return note + bonus\n\nbonus = 0.6\nma_moyenne = 9.5\nma_moyenne = coup_de_pouce(ma_moyenne)\ntest_bac(ma_moyenne)\n
Ce code n'est pas valide, car il contrevient \u00e0 la r\u00e8gle 3.
ligne 4
: la modification de la variable globale points
est interdite.
Ce code n'est pas valide, car il contrevient \u00e0 la r\u00e8gle 1.
ligne 5
: l'acc\u00e8s \u00e0 la variable locale x
est interdit.
Ce code est valide.
ligne 6
: l'acc\u00e8s \u00e0 la variable globale bonus
est autoris\u00e9, selon la r\u00e8gle 2.
\u00c0 propos de la r\u00e8gle n\u00b03
(toute la v\u00e9rit\u00e9, rien que la v\u00e9rit\u00e9)
Pour certains types de variables (listes, dictionnaires...), la modification d'une variable globale \u00e0 l'int\u00e9rieur du corps d'une fonction est en fait possible (contrairement \u00e0 ce qu'\u00e9nonce la r\u00e8gle 3). Mais cela reste tr\u00e8s fortement d\u00e9conseill\u00e9.
Pour les autres types de variables, on peut m\u00eame forcer pour avoir cette possibilit\u00e9 en utilisant le mot global
\u00e0 l'int\u00e9rieur de la fonction.
Mais il faut essayer d'\u00e9viter ceci. Une fonction ne doit (c'est un ordre, mais vous pouvez choisir de l'ignorer, tout comme vous pouvez choisir de passer au feu rouge) modifier que les variables qu'elle cr\u00e9e (ses variables locales) ou bien les variables qu'on lui a donn\u00e9es en param\u00e8tre.
Une fonction qui ne respecte pas cette r\u00e8gle pr\u00e9sente des effets de bord : on peut peut-\u00eatre arriver \u00e0 les g\u00e9rer sur un \u00abpetit\u00bb code, mais cela devient illusoire sur un code utilisant de multiples fonctions.
.
En r\u00e9sum\u00e9
Ne pas faire cela :
# PAS BIEN\nscore = 0\ndef ramasse_objet(objet):\n global score\n if objet == \"champignon\":\n score += 20\n if objet == \"banane\":\n score -= 300\n
>>> ramasse_objet(\"champignon\")\n>>> score\n20\n
Faire plut\u00f4t ceci :
# BIEN\nscore = 0\ndef ramasse_objet(objet, score): # ma fonction veut modifier score ? \n if objet == \"champignon\": # -> ok, je mets score dans ses param\u00e8tres\n score += 20\n if objet == \"banane\":\n score -= 300\n return score # je renvoie le nouveau score\n
>>> score = ramasse_objet(\"champignon\", score)\n>>> score\n20\n
"},{"location":"T1_Demarrer_en_Python/1.5_Fonctions/cours/#6-documenter-une-fonction","title":"6. Documenter une fonction","text":""},{"location":"T1_Demarrer_en_Python/1.5_Fonctions/cours/#61-help","title":"6.1 Help !","text":"Si une fonction peut \u00eatre assimil\u00e9e \u00e0 un outil, il est normal de se demander si cet outil poss\u00e8de un mode d'emploi.
Observons les fonctions pr\u00e9-d\u00e9finies par Python, et notamment une des premi\u00e8res que nous avons rencontr\u00e9es : la fonction print()
. Son mode d'emploi est accessible gr\u00e2ce \u00e0 la commande help(print)
.
>>> help(print)\nHelp on built-in function print in module builtins:\n\nprint(...)\n print(value, ..., sep=' ', end='\\n', file=sys.stdout, flush=False)\n\n Prints the values to a stream, or to sys.stdout by default.\n Optional keyword arguments:\n file: a file-like object (stream); defaults to the current sys.stdout.\n sep: string inserted between values, default a space.\n end: string appended after the last value, default a newline.\n flush: whether to forcibly flush the stream\n
Pensez \u00e0 utiliser cette fonction help()
(en d'autres termes, RTFM)
Il est possible, voire souhaitable (d\u00e8s qu'on cr\u00e9\u00e9 un code comportant plusieurs fonctions, et/ou qui sera amen\u00e9 \u00e0 \u00eatre lu par d'autres personnes), de cr\u00e9er un mode d'emploi pour ses fonctions. On appelle cela \u00e9crire la docstring de la fonction, et c'est tr\u00e8s simple : il suffit de l'encadrer par des triples double-quotes \"\"\"
.
Exemple
def chat_penible(n):\n\"\"\"\n Affiche n fois la chaine de caract\u00e8res \"meoww\"\n \"\"\"\n for k in range(n):\n print(\"meoww\")\n
On peut donc maintenant demander de l'aide pour cette fonction :
>>> help(chat_penible)\nHelp on function chat_penible in module __main__:\n\nchat_penible(n)\n Affiche n fois la chaine de caract\u00e8res \"meoww\"\n
Plus de renseignements sur les docstrings ici
"},{"location":"T1_Demarrer_en_Python/1.5_Fonctions/cours/#7-jeux-de-tests-pour-une-fonction","title":"7. Jeux de tests pour une fonction","text":"Les exercices de cette feuille sont (presque) tous livr\u00e9s avec un jeu de tests. Il s'agit d'une fonction, souvent appel\u00e9e test_nom_de_la fonction()
, qui va regrouper les diff\u00e9rents tests qu'on pourrait faire en console pour v\u00e9rifier que la fonction a le comportement d\u00e9sir\u00e9.
Ces tests reposent sur le mot-cl\u00e9 assert
, qui va lever une erreur lorsqu'il est suivi d'une expression \u00e9valu\u00e9e \u00e0 False
:
>>> assert 3 > 2\n>>> assert 3 > 5\nTraceback (most recent call last):\n File \"<pyshell>\", line 1, in <module>\nAssertionError\n>>> assert True\n>>> assert False\nTraceback (most recent call last):\n File \"<pyshell>\", line 1, in <module>\nAssertionError\n
Exemple d'un jeu de tests
def maxi(n1, n2):\n if n1 < n2 :\n return n2\n else :\n return n1\n\ndef test_maxi():\n assert maxi(3,4) == 4\n assert maxi(5,2) == 5\n assert maxi(7,7) == 7\n print(\"tests ok\")\n
Il faut v\u00e9rifier que les tests couvrent toutes les situations possibles, mais ce n'est pas toujours facile !
Exercice
\u00c9nonc\u00e9CorrectionOn consid\u00e8re (\u00e0 nouveau !) le jeu du FizzBuzz.
Rappel des r\u00e8gles
On souhaite \u00e9crire la fonction fizzbuzz(n)
qui renverra soit le nombre n
, soit le mot par lequel il faut le remplacer.
test_fizzbuzz()
qui testera la fonction fizzbuzz(n)
.fizzbuzz(n)
.def test_fizzbuzz():\n assert fizzbuzz(6) == 'fizz'\n assert fizzbuzz(10) == 'buzz'\n assert fizzbuzz(15) == 'fizzbuzz'\n print('tests ok !')\n\ndef fizzbuzz(n):\n if n % 3 == 0 and n % 5 == 0:\n return 'fizzbuzz'\n elif n % 3 == 0:\n return 'fizz'\n elif n % 5 == 0:\n return 'buzz'\n else:\n return n\n
"},{"location":"T1_Demarrer_en_Python/1.5_Fonctions/exercices/","title":"Exercices","text":"Exercice 1
\u00c9nonc\u00e9Tester sa fonctionCorrection\u00c9crire une fonction maxi
qui prend comme param\u00e8tres deux nombres n1
et n2
et qui renvoie le plus grand \u00e9l\u00e9ment entre n1
et n2
.
Exemple d'utilisation
>>> maxi(3,1)\n3\n
Vous pouvez utiliser la fonction de tests ci-dessous :
def test_maxi():\n assert maxi(3,4) == 4\n assert maxi(5,2) == 5\n assert maxi(7,7) == 7\n print(\"tests ok\")\n
def maxi(n1, n2):\n if n1 < n2 :\n return n2\n else :\n return n1\n
Exercice 2
\u00c9nonc\u00e9Correction\u00c9crire une fonction moyenne
qui prend en param\u00e8tre trois nombres a
, b
et c
et qui renvoie la moyenne de ces trois nombres.
Exemple d'utilisation
>>> moyenne(6, 15, 9)\n10\n
def moyenne(a, b, c):\n return (a + b + c) / 3 \n
Exercice 3
\u00c9nonc\u00e9Correction\u00c9crire une fonction somme
qui prend en param\u00e8tre un entier positif n
et qui renvoie la somme de tous les entier de 1 \u00e0 n
.
\\(S = 1+2+3+4+5+ \\dots +(n-1) + n\\)
Exemple d'utilisation
>>> somme(10)\n55\n
def somme(n):\n s = 0\n for k in range(1, n+1):\n s += k\n return s\n
Exercice 4
\u00c9nonc\u00e9Tester sa fonctionCorrection\u00c9crire une fonction nb_voyelles
qui prend un param\u00e8tre la chaine de caract\u00e8res mot
renvoie le nombre de voyelles de mot
.
Exemple d'utilisation
>>> nb_voyelles(\"bonjour\")\n3\n
Vous pouvez utiliser la fonction de tests ci-dessous :
def test_nb_voyelles():\n assert nb_voyelles(\"bonjour\") == 3\n assert nb_voyelles(\"fdjgdhk\") == 0\n assert nb_voyelles(\"au\") == 2\n print(\"tests ok\")\n
def nb_voyelles(mot):\n voyelles = 'aeiouy'\n nb = 0\n for lettre in mot:\n if lettre in voyelles:\n nb += 1\n return nb\n
Exercice 5
\u00c9nonc\u00e9Tester sa fonctionCorrectionD\u00e9finissez une fonction decale(lettre)
qui d\u00e9cale de 3 rangs dans l'alphabet la lettre majuscule lettre
pass\u00e9e en argument (apr\u00e8s Z, on recommencera \u00e0 A..)
Aide
>>> ord('A')\n65\n>>> chr(65)\n'A'\n
Exemple d'utilisation
>>> decale('F')\n'I'\n
Vous pouvez utiliser la fonction de tests ci-dessous :
def test_decale():\n assert decale('A') == 'D'\n assert decale('Z') == 'C'\n print('tests ok !')\n
def decale(lettre):\n rang_lettre = ord(lettre)\n rang_nouvelle_lettre = rang_lettre + 3\n if rang_nouvelle_lettre > ord('Z'):\n rang_nouvelle_lettre -= 26\n nouvelle_lettre = chr(rang_nouvelle_lettre) \n\n return nouvelle_lettre\n
ou mieux, en utilisant le modulo %
: def decale(lettre):\n rang_ancienne_lettre = ord(lettre) - 65\n rang_nouvelle_lettre = (rang_ancienne_lettre + 3) % 26 + 65 \n nouvelle_lettre = chr(rang_nouvelle_lettre)\n\n return nouvelle_lettre\n
Exercice 6
\u00c9nonc\u00e9Tester sa fonctionCorrectionRajoutez un param\u00e8tre n
\u00e0 la fonction pr\u00e9c\u00e9dente pour pouvoir d\u00e9caler la lettre de n
rangs.
Exemple d'utilisation
>>> decale('B', 5)\n'G'\n
Vous pouvez utiliser la fonction de tests ci-dessous :
def test_decale():\n assert decale('A', 3) == 'D'\n assert decale('A', 5) == 'F'\n assert decale('Z', 1) == 'A'\n print('tests ok !')\n
def decale(lettre, n):\n rang_lettre = ord(lettre)\n rang_nouvelle_lettre = rang_lettre + n\n if rang_nouvelle_lettre > ord('Z'):\n rang_nouvelle_lettre -= 26\n nouvelle_lettre = chr(rang_nouvelle_lettre) \n\n return nouvelle_lettre\n
Exercice 7
\u00c9nonc\u00e9CorrectionUtilisez la fonction pr\u00e9c\u00e9dente pour cr\u00e9er la fonction decale_phrase(p, n)
qui d\u00e9cale toutes les lettres d'une phrase p
de n
rangs. On laissera les espaces intacts.
Exemple d'utilisation
>>> decale_phrase(\"PAS MAL DU TOUT\", 4)\n'TEW QEP HY XSYX'\n
def decale_phrase(p, n):\n phrase_decalee = ''\n for lettre in p:\n if lettre == ' ':\n phrase_decalee += ' '\n else:\n nouvelle_lettre = decale(lettre, n)\n phrase_decalee += nouvelle_lettre\n return phrase_decalee\n
Exercice 8
\u00c9nonc\u00e9CorrectionD\u00e9codez la phrase RT BTHHPVT CT RDCIXTCI GXTC S XCITGTHHPCI
.
def decale(lettre, n):\n rang_lettre = ord(lettre)\n rang_nouvelle_lettre = rang_lettre + n\n if rang_nouvelle_lettre > ord('Z'):\n rang_nouvelle_lettre -= 26\n nouvelle_lettre = chr(rang_nouvelle_lettre) \n\n return nouvelle_lettre\n\ndef decale_phrase(p, n):\n phrase_decalee = ''\n for lettre in p:\n if lettre == ' ':\n phrase_decalee += ' '\n else:\n nouvelle_lettre = decale(lettre, n)\n phrase_decalee += nouvelle_lettre\n return phrase_decalee\n\n\ndef decrypt(msg_secret):\n for decalage in range(25):\n print(decale_phrase(msg_secret, decalage))\n\nmsg = 'RT BTHHPVT CT RDCIXTCI GXTC S XCITGTHHPCI'\n\ndecrypt(msg)\n\n# cette m\u00e9thode impose de tout lire pour y chercher une phrase ayant du sens.\n# Si on sait que la phrase sera en fran\u00e7ais, on peut chercher des mots du\n# dictionnaire. Si par exemple on sait que la phrase contiendra le mot 'MESSAGE',\n# le code peut devenir :\n\n\ndef decrypt2(msg_secret):\n for decalage in range(25):\n phrase_clair = decale_phrase(msg_secret, decalage)\n if 'MESSAGE' in phrase_clair:\n print(phrase_clair)\n\nmsg = 'RT BTHHPVT CT RDCIXTCI GXTC S XCITGTHHPCI'\n\ndecrypt2(msg)\n
Exercice 9
\u00c9nonc\u00e9CorrectionLa conjecture de Syracuse (ou de Collatz) postule ceci :
Prenons un nombre \\(n\\) : si \\(n\\) est pair, on le divise par 2, sinon on le multiplie par 3 puis on ajoute 1. On recommence cette op\u00e9ration tant que possible. Au bout d'un certain temps, on finira toujours par tomber sur le nombre 1.
suivant(n)
qui renvoie le successeur du nombre n
, suivant les r\u00e8gles \u00e9nonc\u00e9es ci-dessus.syracuse(n)
qui affiche tous les termes de la suite de Syracuse jusqu'\u00e0 (on l'esp\u00e8re !) 1. 1.
def suivant(n):\n if n % 2 == 0:\n return n // 2\n else:\n return 3*n + 1\n
2. def syracuse(n):\n print(n)\n while n != 1:\n n = suivant(n)\n print(n)\n
Exercice 10
\u00c9nonc\u00e9Correctiontemps_de_vol(n)
qui renvoie le nombre d'\u00e9tapes pour arriver \u00e0 1, en partant de n
temps_max(nmax)
qui affiche le plus grand temps de vol pour un nombre entre 1 et nmax
.1.
def temps_de_vol(n):\n compteur = 1\n while n != 1:\n compteur += 1\n n = suivant(n)\n return compteur\n
2. def temps_max(nmax):\n maximum = 0\n for k in range(1, nmax + 1):\n duree = temps_de_vol(k)\n if duree > maximum:\n maximum = duree\n print('le plus grand temps de vol vaut :', maximum)\n
"},{"location":"T2_Representation_des_donnees/sommaire/","title":"Th\u00e8me 2 : Repr\u00e9sentation des donn\u00e9es","text":"Les listes font partie de ce qu'on appelle les donn\u00e9es composites (nous verrons plus tard les tuples et les dictionnaires). Elles permettent de regrouper de mani\u00e8re structur\u00e9e un ensemble de valeurs (et non plus une valeur unique). On les appelle listes en Python, ou bien tableaux de mani\u00e8re plus g\u00e9n\u00e9rale.
"},{"location":"T2_Representation_des_donnees/2.1_Listes/cours/#1-declaration-dune-liste","title":"1. D\u00e9claration d'une liste","text":"Exemple fondateur n\u00b01
Une variable de type liste sera d\u00e9limit\u00e9e par des crochets, et ses \u00e9l\u00e9ments s\u00e9par\u00e9s par des virgules :
>>> maliste = [\"riri\", \"fifi\", \"loulou\"]\n
On peut observer le type de la variable ainsi cr\u00e9\u00e9e :
>>> type(maliste)\n<class 'list'>\n
Remarques :
M\u00eame si cela n'a ici un grand int\u00e9r\u00eat, les \u00e9l\u00e9ments d'une liste peuvent donc \u00eatre de types diff\u00e9rents : ici, tous les \u00e9l\u00e9ments de ma liste sont des cha\u00eenes de caract\u00e8res (str
), mais la liste [\"riri\", 5, \"fifi\", \"loulou\"]
est aussi une liste valide.
Une liste vide se d\u00e9clarera avec []
.
>>> copies_corrigees = []\n
Nous verrons plus tard qu'il est fr\u00e9quent dans les exercices de partir d'une liste vide et d'ajouter progressivement des \u00e9l\u00e9ments. Exemple fondateur n\u00b02
On acc\u00e8de \u00e0 un \u00e9l\u00e9ment d'une liste en mettant entre crochets l'indice de l'\u00e9l\u00e9ment (qui commence \u00e0 z\u00e9ro).
>>> famille = [\"Bart\", \"Lisa\", \"Maggie\"] # (1)\n>>> famille[0]\n'Bart'\n>>> famille[1]\n'Lisa'\n>>> famille[2]\n'Maggie'\n>>> famille[3]\nTraceback (most recent call last):\n File \"<pyshell>\", line 1, in <module>\nIndexError: list index out of range\n
Remarques :
Un indice qui d\u00e9passe la valeur \u00a0longueur de la liste -1
provoquera donc une erreur list index out of range
. C'est une erreur tr\u00e8s fr\u00e9quente lorsqu'on manipule des listes.
Il est par contre possible d'utiliser des indices n\u00e9gatifs. On utilise par exemple tr\u00e8s souvent l'indice -1 pour acc\u00e9der au dernier \u00e9l\u00e9ment de la liste, sans avoir \u00e0 conna\u00eetre la longueur de celle-ci :
>>> famille[-1]\n'Maggie'\n
"},{"location":"T2_Representation_des_donnees/2.1_Listes/cours/#3-longueur-dune-liste","title":"3. Longueur d'une liste","text":"Exemple fondateur n\u00b03
La longueur d'une liste sera donn\u00e9e par la fonction len()
, qui renvoie donc un nombre entier positif ou nul.
>>> len(famille)\n3\n
Remarques :
>>> len([])\n0\n
maliste
(non vide) sera donc toujours l'\u00e9l\u00e9ment d'indice len(maliste)-1
. >>> famille[len(famille) - 1]\n'Maggie'\n
Il existe deux m\u00e9thodes pour parcourir s\u00e9quentiellement tous les \u00e9l\u00e9ments d'une liste. Ces deux m\u00e9thodes sont \u00e0 ma\u00eetriser imp\u00e9rativement.
"},{"location":"T2_Representation_des_donnees/2.1_Listes/cours/#41-parcours-par-elements","title":"4.1 Parcours \u00abpar \u00e9l\u00e9ments\u00bb","text":"C'est la m\u00e9thode la plus naturelle, celle d\u00e9j\u00e0 vue lors de la pr\u00e9sentation de la boucle for
. Nous allons simplement it\u00e9rer sur les \u00e9l\u00e9ments de la liste.
Exemple fondateur n\u00b04
Le code :
famille = [\"Bart\", \"Lisa\", \"Maggie\"]\n\nfor membre in famille:\n print(membre)\n
renverra : Bart\nLisa\nMaggie\n
Remarque :
for k in famille:\n print(k)\n
En effet le nom de variable k
est habituellement utilis\u00e9 pour les nombres (les indices, les compteurs...).Exercice 1
\u00c9nonc\u00e9CorrectionApr\u00e8s un r\u00e9f\u00e9rendum, la liste urne
contient uniquement des 'oui'
ou des 'non'
. D\u00e9terminer le vainqueur de ce r\u00e9f\u00e9rendum.
urne = ['oui', 'non', 'non', 'oui', 'oui', 'oui', 'non', 'oui', 'oui', 'oui', 'non', 'oui', 'non', 'non', 'oui', 'non', 'non', 'oui', 'oui', 'oui', 'oui', 'non', 'non', 'oui', 'non', 'oui', 'non', 'non', 'non', 'oui', 'oui', 'oui', 'oui', 'non', 'oui', 'non', 'non', 'oui', 'non', 'non', 'oui', 'non', 'non', 'non', 'non', 'non', 'non', 'non', 'oui', 'non', 'non', 'oui', 'oui', 'non', 'oui', 'oui', 'oui', 'oui', 'oui', 'oui', 'non', 'non', 'oui', 'oui', 'oui', 'oui', 'non', 'non', 'non', 'oui', 'oui', 'oui', 'non', 'non', 'non', 'non', 'oui', 'non', 'non', 'non', 'non', 'non', 'non', 'non', 'non', 'oui', 'non', 'oui', 'non', 'non', 'oui', 'oui', 'non', 'non', 'non', 'oui', 'oui', 'non', 'oui', 'oui', 'non', 'non', 'oui', 'oui', 'oui', 'non', 'oui', 'non', 'oui', 'oui', 'oui', 'oui', 'oui', 'non', 'non', 'non', 'non', 'oui', 'oui', 'oui', 'non', 'oui', 'non', 'oui', 'oui', 'oui', 'oui', 'oui', 'non', 'non', 'oui', 'non', 'non', 'non', 'non', 'non', 'non', 'oui', 'non', 'non', 'oui', 'non', 'non', 'oui', 'non', 'non', 'oui', 'oui', 'oui', 'oui', 'oui', 'oui', 'non', 'oui']\n
urne = ['oui', 'non', 'non', 'oui', 'oui', 'oui', 'non', 'oui', 'oui', 'oui', 'non', 'oui', 'non', 'non', 'oui', 'non', 'non', 'oui', 'oui', 'oui', 'oui', 'non', 'non', 'oui', 'non', 'oui', 'non', 'non', 'non', 'oui', 'oui', 'oui', 'oui', 'non', 'oui', 'non', 'non', 'oui', 'non', 'non', 'oui', 'non', 'non', 'non', 'non', 'non', 'non', 'non', 'oui', 'non', 'non', 'oui', 'oui', 'non', 'oui', 'oui', 'oui', 'oui', 'oui', 'oui', 'non', 'non', 'oui', 'oui', 'oui', 'oui', 'non', 'non', 'non', 'oui', 'oui', 'oui', 'non', 'non', 'non', 'non', 'oui', 'non', 'non', 'non', 'non', 'non', 'non', 'non', 'non', 'oui', 'non', 'oui', 'non', 'non', 'oui', 'oui', 'non', 'non', 'non', 'oui', 'oui', 'non', 'oui', 'oui', 'non', 'non', 'oui', 'oui', 'oui', 'non', 'oui', 'non', 'oui', 'oui', 'oui', 'oui', 'oui', 'non', 'non', 'non', 'non', 'oui', 'oui', 'oui', 'non', 'oui', 'non', 'oui', 'oui', 'oui', 'oui', 'oui', 'non', 'non', 'oui', 'non', 'non', 'non', 'non', 'non', 'non', 'oui', 'non', 'non', 'oui', 'non', 'non', 'oui', 'non', 'non', 'oui', 'oui', 'oui', 'oui', 'oui', 'oui', 'non', 'oui']\n\nnb_oui = 0\nnb_non = 0\nfor vote in urne:\n if vote == 'oui':\n nb_oui += 1\n else:\n nb_non += 1\nprint('pourcentage de oui', 100*nb_oui/len(urne), '%')\nprint('pourcentage de non', 100*nb_non/len(urne), '%')\nprint('-'*10)\nif nb_oui > nb_non:\n print('le oui est vainqueur')\nelif nb_oui < nb_non:\n print('le non est vainqueur')\nelse:\n print('le oui et le non sont \u00e0 \u00e9galit\u00e9')\n
"},{"location":"T2_Representation_des_donnees/2.1_Listes/cours/#42-parcours-par-indice","title":"4.2 Parcours \u00abpar indice\u00bb","text":"Chaque \u00e9l\u00e9ment \u00e9tant accessible par son indice (de 0
\u00e0 len(liste) - 1
), il suffit de faire parcourir \u00e0 une variable i
l'ensemble des entiers de 0
\u00e0 len(liste) - 1
, par l'instruction range(len(liste))
:
Exemple fondateur n\u00b05
Le code :
famille = [\"Bart\", \"Lisa\", \"Maggie\"]\n\nfor i in range(len(famille)):\n print(famille[i])\n
renverra : Bart\nLisa\nMaggie\n
Bonne habitude \u00e0 prendre : nommer sa variable d'indice i
, j
, k
ou indice
mais pas autre chose !
for membre in famille:\n print(membre)\n
Les avantages
index out of range
!Les inconv\u00e9nients
>>> lst = [1, 2, 3]\n>>> for nb in lst:\n nb = nb * 2 # (1)\n\n>>> lst \n[1, 2, 3] # (2)\n
lst
n'a pas chang\u00e9... for i in range(len(famille)):\n print(famille[i])\n
Les avantages
Les inconv\u00e9nients
len()
)index out of range
...Exercice 1
\u00c9nonc\u00e9CorrectionOn donne la liste :
lst = [3, 1, 4, 1, 5, 9]\n
En utilisant un parcours par indice : for i in range(len(lst)):\n print(lst[i])\n
2.
lst = [3, 1, 4, 1, 5, 9]\n\nfor i in range(len(lst)-1, -1, -1):\n print(lst[i])\n
Exercice 2
\u00c9nonc\u00e9Correction 1.Correction 2.Trouvez le nombre qui est exactement \u00e0 la m\u00eame place dans la liste list1
et dans la liste list2
, sachant que les deux listes ont la m\u00eame taille.
for
(une seule !). while
. Quel est l'avantage de la boucle while
? list1 = [8468, 4560, 3941, 3328, 7, 9910, 9208, 8400, 6502, 1076, 5921, 6720, 948, 9561, 7391, 7745, 9007, 9707, 4370, 9636, 5265, 2638, 8919, 7814, 5142, 1060, 6971, 4065, 4629, 4490, 2480, 9180, 5623, 6600, 1764, 9846, 7605, 8271, 4681, 2818, 832, 5280, 3170, 8965, 4332, 3198, 9454, 2025, 2373, 4067]\nlist2 = [9093, 2559, 9664, 8075, 4525, 5847, 67, 8932, 5049, 5241, 5886, 1393, 9413, 8872, 2560, 4636, 9004, 7586, 1461, 350, 2627, 2187, 7778, 8933, 351, 7097, 356, 4110, 1393, 4864, 1088, 3904, 5623, 8040, 7273, 1114, 4394, 4108, 7123, 8001, 5715, 7215, 7460, 5829, 9513, 1256, 4052, 1585, 1608, 3941]\n
list1 = [8468, 4560, 3941, 3328, 7, 9910, 9208, 8400, 6502, 1076, 5921, 6720, 948, 9561, 7391, 7745, 9007, 9707, 4370, 9636, 5265, 2638, 8919, 7814, 5142, 1060, 6971, 4065, 4629, 4490, 2480, 9180, 5623, 6600, 1764, 9846, 7605, 8271, 4681, 2818, 832, 5280, 3170, 8965, 4332, 3198, 9454, 2025, 2373, 4067]\nlist2 = [9093, 2559, 9664, 8075, 4525, 5847, 67, 8932, 5049, 5241, 5886, 1393, 9413, 8872, 2560, 4636, 9004, 7586, 1461, 350, 2627, 2187, 7778, 8933, 351, 7097, 356, 4110, 1393, 4864, 1088, 3904, 5623, 8040, 7273, 1114, 4394, 4108, 7123, 8001, 5715, 7215, 7460, 5829, 9513, 1256, 4052, 1585, 1608, 3941]\n\nfor i in range(len(list1)):\n if list1[i] == list2[i]:\n print(list1[i])\n
list1 = [8468, 4560, 3941, 3328, 7, 9910, 9208, 8400, 6502, 1076, 5921, 6720, 948, 9561, 7391, 7745, 9007, 9707, 4370, 9636, 5265, 2638, 8919, 7814, 5142, 1060, 6971, 4065, 4629, 4490, 2480, 9180, 5623, 6600, 1764, 9846, 7605, 8271, 4681, 2818, 832, 5280, 3170, 8965, 4332, 3198, 9454, 2025, 2373, 4067]\nlist2 = [9093, 2559, 9664, 8075, 4525, 5847, 67, 8932, 5049, 5241, 5886, 1393, 9413, 8872, 2560, 4636, 9004, 7586, 1461, 350, 2627, 2187, 7778, 8933, 351, 7097, 356, 4110, 1393, 4864, 1088, 3904, 5623, 8040, 7273, 1114, 4394, 4108, 7123, 8001, 5715, 7215, 7460, 5829, 9513, 1256, 4052, 1585, 1608, 3941]\n\ni = 0\nwhile list1[i] != list2[i]:\n i += 1\nprint(list1[i])\n
Avantage : on s'arr\u00eate d\u00e8s qu'on a trouv\u00e9 ! Inconv\u00e9nient : on part du principe que ce nombre existe vraiment. Si on ne le trouve pas, on aura une erreur...
Exercice 3
\u00c9nonc\u00e9CorrectionDans la liste
lst = [2428970, 1518306, 4971405, 1690994, 7918102, 4030834, 8830131, 7514856, 7903128, 6307569, 6624056, 5260490, 6447835, 4598783, 9108626, 5045240, 4128269, 4460134, 2497873, 5076659, 8104003, 7604887, 7451976, 4136924, 5691945, 8726293, 7855592, 3562473, 8849129, 6488474, 5303587, 2606124, 5484044, 4559758, 7592232, 2211406, 9974334, 7988936, 7582946, 7668748, 1799997, 3837917, 3196209, 7064342, 2543765, 1182013, 7253381, 1153735, 1037391, 4375946, 4445821, 5965587, 6001887, 4162629, 5235783, 8716582, 4901175, 5445422, 1120005, 8332321, 7075046, 2194175, 5557300, 2887907, 5103214, 2520744, 5104399, 2065665, 3035703, 7890213, 1758301, 3407982, 1355453, 4896338, 7979392, 9671602, 9690721, 7423779, 7423780, 3080825, 6785783, 3836837, 7310931, 1857470, 3492507, 2823231, 1492310, 1911148, 9620515, 5564910, 7009452, 7464745, 9608747, 7267383, 6939140, 6556578, 3592267, 8135497, 4881660, 5346884, 6859150]\n
se cachent deux nombres cons\u00e9cutifs (comme les nombres 4 et 5 dans la liste [6, 2, 4, 5, 3]
). Pouvez-vous les trouver ? lst = [2428970, 1518306, 4971405, 1690994, 7918102, 4030834, 8830131, 7514856, 7903128, 6307569, 6624056, 5260490, 6447835, 4598783, 9108626, 5045240, 4128269, 4460134, 2497873, 5076659, 8104003, 7604887, 7451976, 4136924, 5691945, 8726293, 7855592, 3562473, 8849129, 6488474, 5303587, 2606124, 5484044, 4559758, 7592232, 2211406, 9974334, 7988936, 7582946, 7668748, 1799997, 3837917, 3196209, 7064342, 2543765, 1182013, 7253381, 1153735, 1037391, 4375946, 4445821, 5965587, 6001887, 4162629, 5235783, 8716582, 4901175, 5445422, 1120005, 8332321, 7075046, 2194175, 5557300, 2887907, 5103214, 2520744, 5104399, 2065665, 3035703, 7890213, 1758301, 3407982, 1355453, 4896338, 7979392, 9671602, 9690721, 7423779, 7423780, 3080825, 6785783, 3836837, 7310931, 1857470, 3492507, 2823231, 1492310, 1911148, 9620515, 5564910, 7009452, 7464745, 9608747, 7267383, 6939140, 6556578, 3592267, 8135497, 4881660, 5346884, 6859150]\n\nfor i in range(len(lst)-1): # Il faut s'arr\u00eater \u00e0 l'avant-dernier \u00e9l\u00e9ment de la liste\n if lst[i] + 1 == lst[i+1]:\n print(lst[i], lst[i+1])\n
"},{"location":"T2_Representation_des_donnees/2.1_Listes/cours/#5-modification-dune-liste","title":"5. Modification d'une liste","text":"En Python, les objets de type List
sont modifiables (on emploie le mot mutables). Et c'est souvent une bonne chose, car des listes peuvent \u00e9voluer apr\u00e8s leur cr\u00e9ation. Lorsqu'on souhaitera figer le contenu d'une liste (pour des raisons de s\u00e9curit\u00e9 du code essentiellement), on utilisera alors le type Tuple
, qui sera vu ult\u00e9rieurement.
Il suffit d'\u00e9craser la valeur actuelle avec une nouvelle valeur
Exemple fondateur n\u00b06
>>> famille = [\"Bart\", \"Lisa\", \"Maggie\"]\n>>> famille[0] = \"Bartholomew\" # oui, c'est son vrai nom\n>>> famille\n['Bartholomew', 'Lisa', 'Maggie'] \n
"},{"location":"T2_Representation_des_donnees/2.1_Listes/cours/#52-ajout-dun-element-a-la-fin-dune-liste-la-methode-append","title":"5.2 Ajout d'un \u00e9lement \u00e0 la fin d'une liste : la m\u00e9thode append()","text":"Exemple fondateur n\u00b07
>>> famille = [\"Bart\", \"Lisa\", \"Maggie\"]\n>>> famille.append(\"Milhouse\")\n>>> famille\n['Bart', 'Lisa', 'Maggie', 'Milhouse'] \n
Remarques :
append()
rajoute donc un \u00e9l\u00e9ment \u00e0 la fin de la liste.[]
que l'on remplit peu \u00e0 peu avec des append()
.i
avec la m\u00e9thode insert
: >>> famille = [\"Bart\", \"Lisa\", \"Maggie\"]\n>>> famille.insert(1, \"Nelson\") # on ins\u00e8re \u00e0 la position 1\n>>> famille\n['Bart', 'Nelson', 'Lisa', 'Maggie']\n
Exercice 4
\u00c9nonc\u00e9CorrectionConstruire une liste contenant tous les nombres inf\u00e9rieurs \u00e0 100 qui sont divisibles par 7.
lst = []\nfor n in range(1, 101):\n if n % 7 == 0:\n lst.append(n)\n
Exercice 5
\u00c9nonc\u00e9CorrectionOn consid\u00e8re la liste temp = [4, -5, 8, 10, -1, -2, 7, 13]
. Construire la liste temp_pos
qui ne contient que les \u00e9l\u00e9ments positifs de temp
.
temp = [4, -5, 8, 10, -1, -2, 7, 13]\n\ntemp_pos = []\nfor t in temp:\n if t > 0:\n temp_pos.append(t)\n
"},{"location":"T2_Representation_des_donnees/2.1_Listes/cours/#53-suppression-dun-element-dune-liste","title":"5.3 Suppression d'un \u00e9l\u00e9ment d'une liste ...","text":""},{"location":"T2_Representation_des_donnees/2.1_Listes/cours/#531-par-la-methode-remove","title":"5.3.1 ... par la m\u00e9thode remove()","text":"Exemple fondateur n\u00b07
>>> famille = ['Bart', 'Nelson', 'Lisa', 'Maggie']\n>>> famille.remove(\"Nelson\")\n>>> famille\n['Bart', 'Lisa', 'Maggie']\n
Remarques :
remove
n'enl\u00e8ve que la premi\u00e8re occurrence de l'\u00e9l\u00e9ment d\u00e9sign\u00e9. S'il y en a d'autres apr\u00e8s, elles resteront dans la liste : >>> lst = [3, 1, 4, 5, 1, 9, 4]\n>>> lst.remove(4)\n>>> lst\n[3, 1, 5, 1, 9, 4]\n
>>> lst = [3, 1, 4, 5, 1, 9]\n>>> lst.remove(2)\nTraceback (most recent call last):\n File \"<pyshell>\", line 1, in <module>\nValueError: list.remove(x): x not in list\n
del
","text":"L'instruction del
(qui n'est pas une fonction) permet de supprimer un \u00e9l\u00e9ment en donnant son indice.
>>> maliste = [8, 4, 2, 5, 7]\n>>> del maliste[3]\n>>> maliste\n[8, 4, 2, 7]\n
Exercice 6
\u00c9nonc\u00e9Exercice de la BNS.
"},{"location":"T2_Representation_des_donnees/2.1_Listes/cours/#6-construction-dune-liste-delements-identiques","title":"6. Construction d'une liste d'\u00e9l\u00e9ments identiques","text":"Il est souvent pratique d'initialiser une liste de taille donn\u00e9e, souvent en la remplissant de 0.
Imaginons par exemple que nous souhaitions une liste de taille 26 remplie de 0. Il est possible de faire comme ceci :
lst = []\nfor _ in range(26):\n lst.append(0)\n
mais on pr\u00e9f\u00e8rera ce code :
Exemple fondateur n\u00b08
>>> lst = [0]*26\n
qui produira la liste [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
Exercice 7
\u00c9nonc\u00e9CorrectionQue fait le code ci-dessous ?
texte = \"cet texte est prodigieusement ennuyeux\"\n\ndef rang(lettre):\n return(ord(lettre) - 97)\n\ncompt = [0]*26\nfor lettre in texte :\n if lettre != \" \" :\n compt[rang(lettre)] += 1\n
"},{"location":"T2_Representation_des_donnees/2.1_Listes/cours/#7-construction-dune-liste-en-comprehension","title":"7. Construction d'une liste en compr\u00e9hension","text":"C'est une grande caract\u00e9ristique du langage Python (m\u00eame si ce n'est pas une exclusivit\u00e9) : la m\u00e9thode de liste en compr\u00e9hension propose une mani\u00e8re \u00e9l\u00e9gante, rapide et naturelle pour cr\u00e9er des listes.
"},{"location":"T2_Representation_des_donnees/2.1_Listes/cours/#71-en-comprehension-pourquoi","title":"7.1 \u00aben compr\u00e9hension\u00bb, pourquoi ?","text":"Cette expression vient des math\u00e9matiques. On dit qu'on d\u00e9finit un sous-ensemble par compr\u00e9hension lorsqu'on part d'un ensemble plus grand dont on ne garde que les \u00e9l\u00e9ments v\u00e9rifiant une certaine propri\u00e9t\u00e9.
On pourrait par exemple d\u00e9finir les \u00e9l\u00e8ves de Premi\u00e8re NSI de cette mani\u00e8re :
\u00ab\u00e9l\u00e8ves du lyc\u00e9e inscrits en classe de Premi\u00e8re ayant choisi la sp\u00e9cialit\u00e9 NSI\u00bb
On part d'un ensemble large (les \u00e9l\u00e8ves du lyc\u00e9e) qu'on va ensuite r\u00e9duire par des caract\u00e9risations sp\u00e9cifiques : \u00eatre un \u00e9l\u00e8ve de Premi\u00e8re, puis avoir choisi la sp\u00e9cialit\u00e9 NSI.
"},{"location":"T2_Representation_des_donnees/2.1_Listes/cours/#72-premier-exemple","title":"7.2 Premier exemple","text":"Exemple fondateur n\u00b09
Imaginons que nous poss\u00e9dons une liste data
de temp\u00e9ratures, dont nous ne voulons garder que celles strictement sup\u00e9rieures \u00e0 20.
>>> data = [17, 22, 15, 28, 16, 13, 21, 23]\n>>> good = [t for t in data if t > 20]\n>>> good\n[22, 28, 21, 23]\n
Explications :
"},{"location":"T2_Representation_des_donnees/2.1_Listes/cours/#721-le-filtre-eventuel","title":"7.2.1 le filtre \u00e9ventuel","text":"C'est lui qui donne tout son sens \u00e0 cette m\u00e9thode : il permet de ne garder que certaines valeurs. Il est pourtant \u00e9ventuel : que se passe-t-il s'il n'y a pas de filtre ?
>>> data = [17, 22, 15, 28, 16, 13, 21, 23]\n>>> good = [t for t in data]\n>>> good\n[17, 22, 15, 28, 16, 13, 21, 23]\n
On se retrouve \u00e9videmment avec une nouvelle liste qui contient exactement les \u00e9l\u00e9ments de la liste de d\u00e9part, ce qui n'est pas tr\u00e8s int\u00e9ressant. Pourtant les listes en compr\u00e9hension sans filtre sont tr\u00e8s fr\u00e9quentes, nous le verrons plus loin. Exercice 8
\u00c9nonc\u00e9CorrectionOn consid\u00e8re la variable phrase = 'Bonjour les vacances sont finies'
et la variable voyelles = 'aeiouy'
.
Construire en compr\u00e9hension la liste liste_voyelles
qui contient toutes les voyelles pr\u00e9sentes dans la variable phrase
.
C'est \u00e0 partir de lui que va se construire notre liste. Pour l'instant, cet ensemble de d\u00e9part a toujours \u00e9t\u00e9 de type list
.
Cet ensemble peut \u00eatre aussi donn\u00e9 \u00e0 partir de l'instruction range()
. Souvenons-nous de l'exercice 4 : \u00abConstruire une liste contenant tous les nombres inf\u00e9rieurs \u00e0 100 qui sont divisibles par 7.\u00bb.
Une solution possible \u00e9tait :
lst = []\nfor n in range(1, 101):\n if n % 7 == 0:\n lst.append(n)\n
Ce code peut maintenant s'\u00e9crire tr\u00e8s simplement en une seule instruction :
Exemple fondateur n\u00b010
>>> lst = [n for n in range(1,101) if n % 7 == 0]\n>>> lst\n[7, 14, 21, 28, 35, 42, 49, 56, 63, 70, 77, 84, 91, 98]\n
"},{"location":"T2_Representation_des_donnees/2.1_Listes/cours/#723-la-valeur-a-garder","title":"7.2.3 la valeur \u00e0 garder","text":"Pour l'instant, nous avons proc\u00e9d\u00e9 \u00e0 des filtres sur des ensembles existants, sans modifier la valeur filtr\u00e9e (la valeur \u00e0 garder). Les listes en compr\u00e9hension deviennent encore plus int\u00e9ressantes lorsqu'on comprend qu'il est possible de modifier la valeur filtr\u00e9e :
Exemple fondateur n\u00b011
>>> lst_carres = [t**2 for t in range(1,10)]\n>>> lst_carres\n[1, 4, 9, 16, 25, 36, 49, 64, 81]\n
Exercice 9
\u00c9nonc\u00e9Correctionf
.Exercice 10
\u00c9nonc\u00e9CorrectionOn consid\u00e8re la liste lst = [51, 52, 66, 91, 92, 82, 65, 53, 86, 42, 79, 95]
. Seuls les nombres entre 60 et 90 ont une signification : ce sont des codes ASCII (r\u00e9cup\u00e9rables par la fonction chr
). Cr\u00e9er (en compr\u00e9hension) une liste sol
qui contient les lettres correspondants aux nombres ayant une signification.
une copie un peu trop parfaite
Observez le code ci-dessous, r\u00e9alis\u00e9 sans trucage.
>>> listA = [1, 2, 3]\n>>> listB = listA\n>>> listA.append(7)\n>>> listB\n[1, 2, 3, 7]\n>>> listB.append(8)\n>>> listA\n[1, 2, 3, 7, 8]\n
Tout se passe comme si les listes listA
etlistB
\u00e9taient devenus des clones \u00absynchronis\u00e9s\u00bb depuis l'affectation listB = listA
.
Analyse gr\u00e2ce \u00e0 PythonTutor
L'illustration de PythonTutor nous donne la cl\u00e9 de l'\u00e9nigme :
listA
etlistB
sont en fait un seul et m\u00eame objet.
Comment en avoir le c\u0153ur net ? En observant leur adresse-m\u00e9moire, disponible gr\u00e2ce \u00e0 la fonction id
:
>>> id(listA)\n140485841327616\n>>> id(listB)\n140485841327616\n
Ceci met en \u00e9vidence que la m\u00e9taphore du tiroir dont on se sert pour expliquer ce qu'est une variable est malheureusement inexacte. Une variable est une r\u00e9f\u00e9rence vers une adresse-m\u00e9moire. Si deux variables font r\u00e9f\u00e9rence \u00e0 la m\u00eame adresse-m\u00e9moire, alors elles sont totalement identiques: toute modification de l'une entra\u00eene une modification de l'autre.
Pour en savoir plus sur les variables, vous pouvez revenir sur la partie optionnelle du cours sur les variables.
"},{"location":"T2_Representation_des_donnees/2.1_Listes/cours/#mais-alors-comment-copier-le-contenu-dune-liste-vers-une-autre-sans-creer-un-clone","title":"Mais alors, comment copier le contenu d'une liste vers une autre sans cr\u00e9er un clone ?","text":"Exemple fondateur n\u00b012
>>> listA = [3, 4, 5]\n>>> listB = list(listA)\n
D'autres possibilit\u00e9s existent, comme listA.copy()
, ou encore listA[::]
... Exercice 11
\u00c9nonc\u00e9CorrectionEffectuer les tests n\u00e9cessaires pour prouver que l'exemple pr\u00e9c\u00e9dent a bien produit deux objets diff\u00e9rents.
"},{"location":"T2_Representation_des_donnees/2.1_Listes/cours/#9-tableaux-a-plusieurs-dimensions-listes-de-listes","title":"9. Tableaux \u00e0 plusieurs dimensions : listes de listes","text":"Nous avons vu qu'une liste pouvait contenir des \u00e9l\u00e9ments de tous types : des entiers, des chaines des caract\u00e8res... et pourquoi pas une liste qui contient des listes ?
"},{"location":"T2_Representation_des_donnees/2.1_Listes/cours/#91-syntaxe","title":"9.1 Syntaxe","text":"Exemple fondateur n\u00b012
La liste tab
ci-dessous est compos\u00e9e de 3 listes qui elles-m\u00eames contiennent trois nombres :
tab = [[3, 5, 2],\n [7, 1, 4], \n [8, 6, 9]]\n
tab[0][0] = 3
tab[0][1] = 5
tab[2][1] = 6
tab[1] = [7, 1, 4]
La liste a
est compos\u00e9e de 3 \u00e9l\u00e9ments qui sont eux-m\u00eame des listes de 3 \u00e9l\u00e9ments.
Exercice 12
\u00c9nonc\u00e9CorrectionOn consid\u00e8re le jeu du Morpion (ou Tic-Tac-Toe) dont la surface de jeu vierge est represent\u00e9e par le tableau : tab = [[' ', ' ', ' '], [' ', ' ', ' '], [' ', ' ', ' ']]
Les premiers coups jou\u00e9s sont ceux-ci :
tab[1][1] = 'X'
tab[2][1] = 'O'
tab[2][2] = 'X'
tab[0][0] = 'O'
Quel coup doit maintenant jouer le joueur 'X'
pour s'assurer la victoire ?
Exemple fondateur n\u00b013
Parcours par \u00e9l\u00e9ments :
for ligne in tab:\n for elt in ligne:\n print(elt)\n
Parcours par indice :
for i in range(3):\n for j in range(3):\n print(tab[i][j])\n
Exercice 13
\u00c9nonc\u00e9CorrectionOn consid\u00e8re la liste m
('m' comme matrice) suivante :
m = [[1, 9, 4], [4, 1, 8], [7, 10, 1]]
Quelle est la somme de tous les nombres de la matrice m
?
Exercice 1
\u00c9nonc\u00e9CorrectionR\u00e9solvez le Pyd\u00e9fi propos\u00e9 \u00e0 cette adresse
Vous pouvez vous cr\u00e9er un compte pour valider vos r\u00e9sultats, ce site (g\u00e9r\u00e9 par l'Acad\u00e9mie de Poitiers) est remarquable.
(avec les valeurs de test)
lst = [0, 50, 40, 100, 70, 90, 0]\n\ntotal = 0\nfor i in range(len(lst)-1):\n if lst[i] > lst[i+1]:\n nb_pierres = (lst[i]-lst[i+1])//10 + 1\n total += nb_pierres\n\nprint(total)\n
Exercice 2
\u00c9nonc\u00e9CorrectionOn donne la liste jours
suivante :
jours = [\"lundi\", \"mardi\", \"mercredi\", \"jeudi\", \"vendredi\", \"samedi\", \"dimanche\"]\n
On rappelle que la fonction len
permet d'obtenir le nombre de caract\u00e8res d'une chaine de caract\u00e8res :
>>> len(\"test\")\n4\n
lst1
contenant uniquement les jours comportant 5 lettres.lst2
contenant uniquement les jours comportant la lettre a
dans leur nom.compte_e
qui prend en param\u00e8tre une chaine de caract\u00e8res et qui renvoie le nombre de e
que contient cette chaine de caract\u00e8res.lst4
contenant uniquement les jours comportant deux fois la lettre e
dans leur nom.1.
lst1 = [day for day in jours if len(day) == 5]\n
2. lst2 = [day for day in jours if 'a' in day]\n
def compte_e(mot):\n compteur = 0\n for lettre in mot:\n if lettre == 'e':\n compteur += 1\n return compteur\n
lst4 = [day for day in jours if compte_e(day) == 2]\n
Exercice 3
\u00c9nonc\u00e9CorrectionOn donne le tableau m
suivant :
m = [[17, 71, 75, 89, 45, 10, 54, 26, 59, 47, 57, 64, 44], \\\n [67, 25, 47, 49, 28, 40, 10, 17, 77, 35, 87, 15, 68], \\\n [66, 89, 28, 43, 16, 14, 12, 21, 68, 22, 14, 18, 59], \\\n [60, 35, 30, 23, 22, 37, 49, 89, 82, 80, 85, 28, 17], \\\n [61, 42, 39, 46, 29, 38, 85, 72, 44, 60, 47, 35, 52], \\\n [44, 28, 24, 40, 71, 71, 46, 25, 78, 54, 66, 84, 52], \\\n [29, 71, 7, 38, 71, 60, 71, 60, 16, 82, 35, 39, 23], \\\n [18, 61, 38, 7, 8, 32, 67, 43, 23, 28, 29, 16, 30], \\\n [45, 30, 74, 9, 84, 78, 11, 80, 42, 64, 9, 39, 26], \\\n [78, 57, 54, 66, 57, 63, 10, 42, 61, 19, 26, 25, 53], \\\n [38, 87, 10, 64, 75, 26, 14, 68, 19, 33, 75, 50, 18], \\\n [52, 81, 24, 67, 37, 78, 17, 19, 61, 82, 57, 24, 54]]\n
Afficher successivement chaque ligne du tableau en respectant les r\u00e8gles suivantes : *
, sinon afficher une espace
end = ''
\u00e0 la fonction print
. (exemple : print('*', end = '')
)print()
m = [[17, 71, 75, 89, 45, 10, 54, 26, 59, 47, 57, 64, 44], \\\n [67, 25, 47, 49, 28, 40, 10, 17, 77, 35, 87, 15, 68], \\\n [66, 89, 28, 43, 16, 14, 12, 21, 68, 22, 14, 18, 59], \\\n [60, 35, 30, 23, 22, 37, 49, 89, 82, 80, 85, 28, 17], \\\n [61, 42, 39, 46, 29, 38, 85, 72, 44, 60, 47, 35, 52], \\\n [44, 28, 24, 40, 71, 71, 46, 25, 78, 54, 66, 84, 52], \\\n [29, 71, 7, 38, 71, 60, 71, 60, 16, 82, 35, 39, 23], \\\n [18, 61, 38, 7, 8, 32, 67, 43, 23, 28, 29, 16, 30], \\\n [45, 30, 74, 9, 84, 78, 11, 80, 42, 64, 9, 39, 26], \\\n [78, 57, 54, 66, 57, 63, 10, 42, 61, 19, 26, 25, 53], \\\n [38, 87, 10, 64, 75, 26, 14, 68, 19, 33, 75, 50, 18], \\\n [52, 81, 24, 67, 37, 78, 17, 19, 61, 82, 57, 24, 54]]\n\nfor ligne in m:\n for elt in ligne:\n if elt % 7 == 0:\n print('*', end = '')\n else:\n print(' ', end = '')\n print('')\n
Exercice 4
\u00c9nonc\u00e9CorrectionR\u00e9solvez le pyd\u00e9fi Insaisissable matrice propos\u00e9 \u00e0 cette adresse
M=[[17, 3, 4, 14, 5, 17], [8, 16, 3, 17, 14, 12], [13, 5, 15, 4, 16, 3], [14, 7, 3, 16, 3, 2], [6, 1, 16, 10, 5, 13], [11, 1, 9, 11, 18, 8]]\n\ndef f(k):\n return (9*k + 3) % 19\n\nfor _ in range(39):\n for i in range(6):\n for j in range(6):\n M[i][j] = f(M[i][j])\n\nsomme = 0\nfor i in range(6):\n for j in range(6):\n somme += M[i][j]\n\nprint(somme)\n
Exercice 5
\u00c9nonc\u00e9CorrectionD'apr\u00e8s Advent Of Code 2021, day02
Un sous-marin peut se d\u00e9placer horizontalement (toujours vers la droite) gr\u00e2ce \u00e0 l'instruction forward
suivie d'un nombre.
Il peut aussi monter ou descendre, gr\u00e2ce aux instructions up
ou down
, elles aussi suivies d'un nombre.
Un grand nombre d'instructions successives sont donn\u00e9es. Le but de l'exercice est de trouver le produit final de l'abscisse du sous-marin et de sa profondeur.
Exemple :
forward 5\ndown 5\nforward 8\nup 3\ndown 8\nforward 2\n
Apr\u00e8s ces d\u00e9placements, le sous-marin se trouve \u00e0 l'abscisse 15 et \u00e0 la profondeur 10. La r\u00e9ponse \u00e0 l'\u00e9nigme serait donc 150.
\u00e9nonc\u00e9 orginal
T\u00e9l\u00e9chargez le fichier input1.txt. Votre fichier .py
de travail doit se situer dans le m\u00eame r\u00e9pertoire que le fichier input1.txt
.
Q1. Nous allons r\u00e9cup\u00e9rer toutes les donn\u00e9es (on dit parser les donn\u00e9es) dans une liste, gr\u00e2ce \u00e0 l'instruction :
data_str = open('input1.txt').read().splitlines()\n
Combien cette liste comporte-t-elle d'\u00e9l\u00e9ments ? Q2. Afficher successivement tous les \u00e9l\u00e9ments de cette liste.
Q3. Pour s\u00e9parer une chaine de caract\u00e8res en une liste de plusieurs chaines de caract\u00e8res, nous pouvons utiliser la fonction split
:
>>> \"hello world\".split(\" \")\n['hello', 'world']\n
Gr\u00e2ce \u00e0 cette fonction split
, affichez successivement uniquement les instructions forward
, up
ou down
. Q4. Appelons x
et y
l'abscisse et l'ordonn\u00e9e (initialis\u00e9es \u00e0 0) du sous-marin. Que valent x
et y
\u00e0 la fin des instructions ?
On rappelle que la fonction int
permet de convertir une chaine de caract\u00e8res en nombre :
>>> int('4')\n4\n
data_str = open('input1.txt').read().splitlines()\n\nfor ligne in data_str:\n lst = ligne.split(' ')\n if lst[0] == 'forward':\n x += int(lst[1])\n elif lst[0] == 'down':\n y += int(lst[1])\n else:\n y -= int(lst[1])\n\nprint(x*y)\n
"},{"location":"T2_Representation_des_donnees/2.2_Tuples/cours/","title":"2.2 Tuples","text":""},{"location":"T2_Representation_des_donnees/2.2_Tuples/cours/#1definition-des-tuples","title":"1.D\u00e9finition des tuples","text":"Les tuples (appel\u00e9s p-uplets dans le programme officiel de NSI) sont une collection d'objets ordonn\u00e9e mais NON MODIFIABLE. Pour rappel :
Quel peut \u00eatre l'int\u00e9r\u00eat d'un tuple par rapport \u00e0 une liste ?
>>> monPremierTuple = (3, 5, 6)\n
Un tuple se diff\u00e9rencie d'une liste par l'utilisation des parenth\u00e8ses au lieu des crochets.
>>> type(monPremierTuple)\ntuple\n
\u00c0 noter qu'un tuple peut \u00eatre d\u00e9clar\u00e9 sans parenth\u00e8ses. C'est toutefois \u00e0 \u00e9viter.
>>> taille = 600, 800\n>>> type(taille)\ntuple\n
"},{"location":"T2_Representation_des_donnees/2.2_Tuples/cours/#2-acces-aux-elements-dun-tuple","title":"2. Acc\u00e8s aux \u00e9l\u00e9ments d'un tuple","text":"Comme pour une liste ou une cha\u00eene de caract\u00e8re, l'acc\u00e8s se fait par un indice entre crochets.
>>> a = (12, 25, 6)\n>>> a[0]\n12\n
"},{"location":"T2_Representation_des_donnees/2.2_Tuples/cours/#3-tentative-de-modification-dun-tuple","title":"3. Tentative de modification d'un tuple","text":">>> a[0] = 4\n ---------------------------------------------------------------------------\n TypeError Traceback (most recent call last)\n\n <ipython-input-7-5fe525706b2b> in <module>()\n ----> 1 a[0] = 4\n\n\n TypeError: 'tuple' object does not support item assignment\n
"},{"location":"T2_Representation_des_donnees/2.2_Tuples/cours/#4-parcours-dun-tuple","title":"4. Parcours d'un tuple","text":"On retrouve bien \u00e9videmment les deux m\u00e9thodes utilisables pour les listes :
"},{"location":"T2_Representation_des_donnees/2.2_Tuples/cours/#41-parcours-par-indice","title":"4.1 Parcours par indice","text":">>> for k in range(len(a)):\n print(a[k])\n12\n25\n6\n
"},{"location":"T2_Representation_des_donnees/2.2_Tuples/cours/#41-parcours-par-element","title":"4.1 Parcours par \u00e9l\u00e9ment","text":">>> for k in a :\n print(k)\n12\n25\n6\n
"},{"location":"T2_Representation_des_donnees/2.2_Tuples/cours/#5-construction-dune-fonction-renvoyant-un-tuple","title":"5. Construction d'une fonction renvoyant un tuple","text":"def division(a, b):\n # fonction renvoyant le tuple (quotient, reste) de la division euclidienne de a par b.\n q = a // b\n r = a % b\n return (q, r)\n
>>> division(49,12)\n(4,1)\n
"},{"location":"T2_Representation_des_donnees/2.2_Tuples/cours/#6-exercice","title":"6. Exercice","text":"Exercice
\u00c9nonc\u00e9CorrectionOn consid\u00e8re deux points A et B d'un rep\u00e8re quelconque. Leurs coordonn\u00e9es sont des tuples \u00e0 deux \u00e9l\u00e9ments. \u00c9crire une fonction qui prend en argument les coordonn\u00e9es de deux points et qui renvoie le milieu de ces deux points.
La fonction doit fonctionner de cette mani\u00e8re :
>>> C = (45, 12)\n>>> D = (49, 32)\n>>> milieu(C,D)\n(47, 22)\n
"},{"location":"T2_Representation_des_donnees/2.3_Dictionnaires/cours/","title":"2.3 Dictionnaires","text":""},{"location":"T2_Representation_des_donnees/2.3_Dictionnaires/cours/#1-les-dictionnaires-premiers-exemples","title":"1. Les dictionnaires : premiers exemples","text":"Une liste est un ensemble d'\u00e9l\u00e9ments accessibles par leur indice. Cet indice est en quelque sorte la \u00abplace\u00bb de l'\u00e9l\u00e9ment dans la liste. On peut dire que cet indice est la cl\u00e9 qui permet d'acc\u00e9der \u00e0 l'\u00e9l\u00e9ment.
Dans un dictionnaire, chaque \u00e9l\u00e9ment est accessible par une cl\u00e9 qui n'est plus forc\u00e9ment un nombre : une chaine de caract\u00e8re, un nombre, ou autre chose, peut \u00eatre une cl\u00e9.
Imaginons que je fasse l'inventaire de mon dressing :
habits quantit\u00e9 pantalons 3 pulls 4 tee-shirts 8Exemple fondateur n\u00b01
>>> dressing = {\"pantalons\":3, \"pulls\":4, \"tee-shirts\":8}\n
>>> dressing[\"pulls\"]\n 4\n
On dit que \"pulls\"
est la cl\u00e9 et que 4 est la valeur associ\u00e9e \u00e0 la cl\u00e9.
Un dictionnaire est un ensemble cl\u00e9s / valeurs.
Attention : une cl\u00e9 peut aussi \u00eatre un nombre :
>>> myst = {9:4, 1:2, 6:3, 7:4} \n>>> myst[1]\n2\n>>> myst[7]\n4 \n
"},{"location":"T2_Representation_des_donnees/2.3_Dictionnaires/cours/#2-definitions-et-proprietes-dun-dictionnaire","title":"2. D\u00e9finitions et propri\u00e9t\u00e9s d'un dictionnaire","text":""},{"location":"T2_Representation_des_donnees/2.3_Dictionnaires/cours/#21-definitions","title":"2.1 D\u00e9finitions","text":"D\u00e9finition
Un dictionnaire est une donn\u00e9e composite qui n'est pas ordonn\u00e9e (\u00e0 la diff\u00e9rence des listes !) Il fonctionne par un syst\u00e8me de cl\u00e9:valeur
. Les cl\u00e9s, comme les valeurs, peuvent \u00eatre de types diff\u00e9rents. Un dictionnaire est d\u00e9limit\u00e9 par des accolades.
Rappel :
[ ]
-> listes( )
-> tuples{ }
-> dictionnaires.keys()
et .values()
","text":"Exemples fondateurs n\u00b02
>>> dressing.keys()\ndict_keys(['pantalons', 'pulls', 'tee-shirts'])\n
>>> dressing.values()\ndict_values([3, 4, 8])\n
Ces m\u00e9thodes sont importantes (elles figurent explicitement au programme de NSI) mais sont en pratique peu utilis\u00e9es. On leur pr\u00e9f\u00e8rera tr\u00e8s largement la m\u00e9thode de parcours suivante :
"},{"location":"T2_Representation_des_donnees/2.3_Dictionnaires/cours/#23-parcours-dun-dictionnaire","title":"2.3 Parcours d'un dictionnaire","text":"Exemple fondateur n\u00b03
>>> for habit in dressing:\n print(dressing[habit])\n3\n4\n8\n
Observation gr\u00e2ce \u00e0 PythonTutor
"},{"location":"T2_Representation_des_donnees/2.3_Dictionnaires/cours/#24-creation-dun-dictionnaire-vide","title":"2.4 Cr\u00e9ation d'un dictionnaire vide","text":"
Exemple fondateur n\u00b04
Deux m\u00e9thodes existent pour cr\u00e9er un dictionnaire : dict()
et {}
>>> mondico = dict()\n>>> mondico\n{}\n>>> mondico['john'] = 12\n>>> mondico\n{'john': 12}\n
>>> contacts = {}\n>>> contacts['bob'] = '06 12 17 21 32'\n
"},{"location":"T2_Representation_des_donnees/2.3_Dictionnaires/cours/#25-ajout-modification-dun-element-dans-un-dictionnaire","title":"2.5 Ajout / Modification d'un \u00e9l\u00e9ment dans un dictionnaire","text":"Exemple fondateur n\u00b05
Pas besoin d'une m\u00e9thode append()
, il suffit de rajouter une paire cl\u00e9 : valeur
>>> dressing[\"chaussettes\"] = 12\n
On peut aussi modifier un dictionnaire existant.
dressing[\"chaussettes\"] = 11\n
"},{"location":"T2_Representation_des_donnees/2.3_Dictionnaires/cours/#26-suppression-dune-valeur","title":"2.6 Suppression d'une valeur","text":"Exemple fondateur n\u00b06
On utilise l'instruction del
(d\u00e9j\u00e0 rencontr\u00e9e pour les listes)
del dressing[\"chaussettes\"]\n
Exercice 1
\u00c9nonc\u00e9CorrectionReprenons notre dictionnaire dressing
:
dressing = {\"pantalons\":3, \"pulls\":4, \"tee-shirts\":8}\n
Cr\u00e9er une fonction achat(habit)
qui augmente de 1 le nombre d'habits (pantalon, pull ou tee-shirt) de mon dressing. dressing = {\"pantalons\":3, \"pulls\":4, \"tee-shirts\":8}\n\ndef achat(habit):\n dressing[habit] += 1\n
Remarque : Petit probl\u00e8me si on essaie d'acheter un v\u00eatement pour la 1\u00e8re fois
>>> achat(\"chemises\")\n ---------------------------------------------------------------------------\n\n KeyError Traceback (most recent call last)\n\n <ipython-input-28-fd9d1ac5f62d> in <module>\n ----> 1 achat(\"chemises\")\n\n\n <ipython-input-27-feb173444189> in achat(habit)\n 1 def achat(habit):\n ----> 2 dressing[habit] = dressing[habit] + 1\n\n\n KeyError: 'chemises'\n
Nous allons r\u00e9soudre ce probl\u00e8me gr\u00e2ce \u00e0 :
"},{"location":"T2_Representation_des_donnees/2.3_Dictionnaires/cours/#27-test-dappartenance-a-un-dictionnaire","title":"2.7 Test d'appartenance \u00e0 un dictionnaire","text":"Exemple fondateur n\u00b07
Le mot in
permet de tester l'appartenance d'une cl\u00e9 \u00e0 un dictionnaire. Un bool\u00e9en est renvoy\u00e9.
>>> \"cravates\" in dressing\n False\n
"},{"location":"T2_Representation_des_donnees/2.3_Dictionnaires/cours/#3-exercices","title":"3. Exercices","text":"Exercice 2
\u00c9nonc\u00e9CorrectionAm\u00e9liorer la fonction achat(habit)
en y incluant un test pour prendre en compte les nouveaux habits.
def achat(habit):\n if habit in dressing:\n dressing[habit] += 1\n else:\n dressing[habit] = 1\n
Exercice 3
\u00c9nonc\u00e9CorrectionOn consid\u00e8re la liste suivante :
lst = ['Samuel', 'Pauline', 'Lina', 'Lina', 'Louis', 'Wa\u00ebll', 'Cl\u00e9ment', 'Khaled', 'Alexandre', 'Elie', 'Khaled', 'Khaled', 'Armand', 'Lina', 'Louis', 'Lina', 'Lina', 'Elie', 'Jules', 'Louis', 'Cl\u00e9ment', 'Khaled', 'Jules-Evan', 'Lina', 'Jules', 'Hadzo', 'Zoran', 'Cl\u00e9ment', 'Armand', 'Louis', 'Elie', 'Lina', 'Alexandre', 'Khaled', 'Iris', 'Gianni', 'Gianni', 'Pauline', 'Gianni', 'Elie', 'Iris', 'Armand', 'Louis', 'Cl\u00e9ment', 'Pauline', 'Zoran', 'Khaled', 'Zoran', 'Elie', 'Wa\u00ebll', 'Pauline', 'Lina', 'Alexandre', 'Khaled', 'Mehmet', 'Khaled', 'Hadzo', 'Zoran', 'Gianni', 'Jules', 'Paul', 'Pauline', 'Cl\u00e9ment', 'Alexandre', 'Iris', 'Khaled', 'Gianni', 'Elie', 'Jules', 'Khaled', 'Louis', 'Jules-Evan', 'Jules-Evan', 'Louis', 'Gianni', 'Elie', 'Cl\u00e9ment', 'Khaled', 'Louis', 'Louis', 'Emrys', 'Jules', 'Pauline', 'Armand', 'Elie', 'Jules', 'Elie', 'Khaled', 'Cl\u00e9ment', 'Louis', 'Khaled', 'Emrys', 'Samuel', 'Hadzo', 'Elie', 'Cl\u00e9ment', 'Alexandre', 'Hadzo', 'Lina', 'Iris', 'Alexandre', 'Mehmet', 'Elie', 'Jules', 'Khaled', 'Pauline', 'Samuel', 'Armand', 'Mehmet', 'Cl\u00e9ment', 'Jules', 'Armand', 'Mehmet', 'Lina', 'Armand', 'Cl\u00e9ment', 'Hadzo', 'Cl\u00e9ment', 'Emrys', 'Samuel', 'Zoran', 'Zoran', 'Zoran', 'Mehmet', 'Jules', 'Khaled', 'Khaled', 'Elie', 'Armand', 'Jules', 'Alexandre', 'Alexandre', 'Louis', 'Armand', 'Zoran', 'Iris', 'Cl\u00e9ment', 'Mehmet', 'Armand', 'Armand', 'Khaled', 'Lina', 'Lina', 'Jules', 'Louis', 'Paul', 'Pauline', 'Pauline', 'Pauline', 'Khaled', 'Lina', 'Wa\u00ebll', 'Zoran', 'Hadzo', 'Emrys', 'Gianni', 'Jules', 'Samuel', 'Gianni', 'Pauline', 'Wa\u00ebll', 'Cl\u00e9ment', 'Khaled', 'Jules', 'Jules', 'Louis', 'Zoran', 'Alexandre', 'Iris', 'Paul', 'Emrys', 'Armand', 'Wa\u00ebll', 'Zoran', 'Jules', 'Lina', 'Elie', 'Paul', 'Elie', 'Armand', 'Jules-Evan', 'Zoran', 'Alexandre', 'Zoran', 'Elie', 'Elie', 'Elie', 'Lina', 'Armand', 'Louis', 'Zoran', 'Lina', 'Armand', 'Alexandre', 'Samuel', 'Iris', 'Zoran', 'Paul', 'Pauline', 'Jules', 'Armand', 'Jules', 'Iris', 'Iris', 'Jules', 'Alexandre', 'Jules-Evan', 'Jules', 'Iris', 'Iris', 'Armand', 'Lina', 'Pauline', 'Zoran', 'Zoran', 'Pauline', 'Mehmet']\n
Cr\u00e9er un dictionnaire qui associera \u00e0 chaque pr\u00e9nom son nombre d'occurrences dans la liste.
occurrence = {}\n\nfor prenom in lst:\n if prenom in occurrence:\n occurrence[prenom] += 1\n else:\n occurrence[prenom] = 1\n
Exercice 4
\u00c9nonc\u00e9CorrectionOn consid\u00e8re la liste suivante : lst = ['5717', '1133', '5545', '4031', '6398', '2734', '3070', '1346', '7849', '7288', '7587', '6217', '8240', '5733', '6466', '7972', '7341', '6616', '5061', '2441', '2571', '4496', '4831', '5395', '8584', '3033', '6266', '2452', '6909', '3021', '5404', '3799', '5053', '8096', '2488', '8519', '6896', '7300', '5914', '7464', '5068', '1386', '9898', '8313', '1072', '1441', '7333', '5691', '6987', '5255']
Quel est le chiffre qui revient le plus fr\u00e9quemment dans cette liste ?
lst = ['5717', '1133', '5545', '4031', '6398', '2734', '3070', '1346', '7849', '7288', '7587', '6217', '8240', '5733', '6466', '7972', '7341', '6616', '5061', '2441', '2571', '4496', '4831', '5395', '8584', '3033', '6266', '2452', '6909', '3021', '5404', '3799', '5053', '8096', '2488', '8519', '6896', '7300', '5914', '7464', '5068', '1386', '9898', '8313', '1072', '1441', '7333', '5691', '6987', '5255']\n\nocc = {}\n\nfor nombre in lst:\n for chiffre in nombre:\n if chiffre in occ:\n occ[chiffre] += 1\n else:\n occ[chiffre] = 1\n\n# d\u00e9termination du max:\nocc_max = 0\n\nfor chiffre in occ:\n if occ[chiffre] > occ_max:\n occ_max = occ[chiffre]\n chiffre_max = chiffre\n\nprint(chiffre_max, 'est le chiffre le plus fr\u00e9quent')\nprint('il apparait', occ_max, 'fois')\n
Exercice 5
Exercice de bac
"},{"location":"T2_Representation_des_donnees/2.4_Bases/cours/","title":"2.4 Repr\u00e9sentation d'un entier positif dans diff\u00e9rentes bases","text":"Hormis la base 10, deux bases sont utilis\u00e9es en informatique :
Dans toute la suite, la base dans laquelle le nombre est \u00e9crit sera pr\u00e9cis\u00e9e en indice. Exemple : \\(13_{10}=1101_2=\\rm{D}_{16}\\)
"},{"location":"T2_Representation_des_donnees/2.4_Bases/cours/#1-le-systeme-binaire","title":"1. Le syst\u00e8me binaire","text":"En base 2, on ne dispose que des chiffres 0
et 1
. Le syst\u00e8me binaire est un syst\u00e8me de num\u00e9ration de position (comme le syst\u00e8me d\u00e9cimal, hexad\u00e9cimal... mais pas comme le syst\u00e8me romain). \u00c0 chaque rang correspond une puissance de 2.
\\(11010010_2=1 \\times 2^7+ 1 \\times 2^6+0 \\times 2^5+1 \\times 2^4+0 \\times 2^3+0 \\times 2^2+1 \\times 2^1+0 \\times 2^0=128+64+32+2=210_{10}\\)
Le nombre binaire 11010010 correspond donc au nombre d\u00e9cimal 210.
Code Python
En Python, on peut utiliser la fonction int(\"nombre\", base)
.
>>> int(\"11010010\", 2)\n210\n
"},{"location":"T2_Representation_des_donnees/2.4_Bases/cours/#12-du-decimal-vers-le-binaire","title":"1.2 Du d\u00e9cimal vers le binaire :","text":"Principe : dans chaque nombre d\u00e9cimal, il existe une plus grande puissance de 2 qui est inf\u00e9rieure au nombre.
Par exemple, dans 243, il y a 128. Donc \\(243=128 + (115)\\) \\(243=128+64+(51)\\) \\(243=128+64+32+(19)\\) \\(243=128+64+32+16+(3)\\) \\(243=128+64+32+16+2+1\\) \\(243=1 \\times 2^7+ 1 \\times 2^6+1 \\times 2^5+1 \\times 2^4+0 \\times 2^3+0 \\times 2^2+1 \\times 2^1+1 \\times 2^0\\)
Donc \\(243_{10}=11110011_2\\)
M\u00e9thode des divisions successives
Code Python
En Python, on peut utiliser la fonction bin(nombre)
. Elle renvoie une cha\u00eene de caract\u00e8re o\u00f9 le nombre binaire est pr\u00e9c\u00e9d\u00e9 de '0b'
.
>>> bin(243)\n'0b11110011'\n
Exercice 1
\u00c9nonc\u00e9CorrectionQuelle est la valeur maximale d'un octet (un octet = 8 chiffres binaires) ?
\\(11111111_2=255\\). On retrouve ce nombre comme \u00e9tant la valeur maximale d'une composante de couleur dans le codage RGB, ce qui signifie que chaque composante est cod\u00e9e sur un octet.
Exercice 2
\u00c9nonc\u00e9CorrectionCr\u00e9er une fonction binaire(n)
qui renvoie l'\u00e9criture binaire de n
, en utilisant les divisions successives.
def restes_successifs(n):\n''' renvoie la liste des restes successifs lors des divisions de n par 2'''\n restes = []\n while n != 0 :\n restes.append(n % 2)\n n = n // 2\n return restes\n\ndef binaire(n) :\n''' recompose le mot binaire en mettant dans l'ordre les restes successifs'''\n liste = restes_successifs(n)\n liste.reverse() #permet d'inverser l'ordre des \u00e9l\u00e9ment d'une liste\n mot = \"\"\n for k in liste :\n mot += str(k)\n return mot\n
"},{"location":"T2_Representation_des_donnees/2.4_Bases/cours/#2-le-systeme-hexadecimal","title":"2. Le syst\u00e8me hexad\u00e9cimal","text":"L'inconv\u00e9nient essentiel du syst\u00e8me binaire est la longueur de l'\u00e9criture des nombres qu'il g\u00e9n\u00e8re. Pour cette raison, le syst\u00e8me hexad\u00e9cimal, ou syst\u00e8me de base 16 est tr\u00e8s souvent employ\u00e9.
Pour \u00e9crire en base 2, il faut 2 chiffres diff\u00e9rents : le 0 et le 1.
Pour \u00e9crire en base 10, il faut 10 chiffres diff\u00e9rents: 0,1,2,3,4,5,6,7,8,9.
Pour \u00e9crire en base 16, il faut donc 16 chiffres diff\u00e9rents : 0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F.
On a donc la correspondance :
\\(\\rm{1D2}_{16}=1 \\times 16^2+ 13 \\times 16^1+2 \\times 16^0=256+208+2=466_{10}\\)
Le nombre hexad\u00e9cimal 1D2
correspond donc au nombre d\u00e9cimal 466.
En pratique, l'hexad\u00e9cimal est surtout utilis\u00e9 pour sa capacit\u00e9 \u00e0 repr\u00e9senter la valeur de n'importe quel octet sur 2 chiffres (\"chiffres\" \u00e9tant \u00e0 prendre au sens large = chiffres ou lettres !).
Exercice 3
\u00c9nonc\u00e9CorrectionFF
, 3A
, B2
.#8AFF33
.html
du blanc ?On peut utiliser la fonction hex(nombre)
. Elle renvoie une cha\u00eene de caract\u00e8re o\u00f9 le nombre hexad\u00e9cimal est pr\u00e9c\u00e9d\u00e9 de '0x'
.
>>> hex(125)\n'0x7d'\n
"},{"location":"T2_Representation_des_donnees/2.4_Bases/cours/#222-pour-passer-de-lhexadecimal-au-decimal","title":"2.2.2 Pour passer de l'hexad\u00e9cimal au d\u00e9cimal :","text":"On peut utiliser la fonction int(\"nombre\",base)
.
>>> int(\"FF\", 16)\n 255\n
"},{"location":"T2_Representation_des_donnees/2.4_Bases/cours/#3-du-binaire-inattendu","title":"3. Du binaire inattendu","text":"Le message secret de Perseverance
"},{"location":"T2_Representation_des_donnees/2.5_Booleens/05_Operateurs_booleens/","title":"Les op\u00e9rateurs bool\u00e9ens","text":""},{"location":"T2_Representation_des_donnees/2.5_Booleens/05_Operateurs_booleens/#reperes-historiques","title":"Rep\u00e8res historiques","text":"En 1847, le britannique George BOOLE inventa un formalisme permettant d'\u00e9crire des raisonnements logiques : l'alg\u00e8bre de Boole. La notion m\u00eame d'informatique n'existait pas \u00e0 l'\u00e9poque, m\u00eame si les calculs \u00e9taient d\u00e9j\u00e0 automatis\u00e9s (penser \u00e0 la Pascaline de 1642).
Bien plus tard, en 1938, les travaux de l'am\u00e9ricain Claude SHANNON prouva que des circuits \u00e9lectriques peuvent r\u00e9soudre tous les probl\u00e8mes que l'alg\u00e8bre de Boole peut elle-m\u00eame r\u00e9soudre. Pendant la deuxi\u00e8me guerre mondiale, les travaux d'Alan TURING puis de John VON NEUMANN poseront d\u00e9finitivement les bases de l'informatique moderne.
"},{"location":"T2_Representation_des_donnees/2.5_Booleens/05_Operateurs_booleens/#algebre-de-boole","title":"Alg\u00e8bre de Boole","text":"L'alg\u00e8bre de Boole d\u00e9finit des op\u00e9rations dans un ensemble qui ne contient que deux \u00e9l\u00e9ments not\u00e9s 0 et 1, ou bien FAUX et VRAI ,ou encore False et True (en Python)
Les op\u00e9rations fondamentales sont : - la conjonction (\"ET\") - la disjonction (\"OU\") - la n\u00e9gation (\"NON\").
Dans toute la suite, x
et y
d\u00e9signeront des Bool\u00e9ens (\u00e9l\u00e9ments d'une alg\u00e8bre de Boole) quelconques, F
d\u00e9signera FAUX et V
d\u00e9signera VRAI.
and
.
C'est l'op\u00e9ration d\u00e9finie par:
x & F = F
x & V = x
Puisque l'alg\u00e8bre de Boole ne contient que deux \u00e9l\u00e9ments, on peut \u00e9tudier tous les cas possibles et les regrouper dans un tableau appel\u00e9 table de v\u00e9rit\u00e9:
x
y
x & y
F F F F V F V F F V V V On repr\u00e9sente souvent les op\u00e9rateurs bool\u00e9ens \u00e0 l'aide de portes logiques:
Notation usuelle en \u00e9lectronique : \\(Q=A \\wedge B\\)
"},{"location":"T2_Representation_des_donnees/2.5_Booleens/05_Operateurs_booleens/#exemples-en-python","title":"Exemples en Python","text":"n = 20\n
(n % 10 == 0) and (n % 7 == 0)\n
False\n
(n % 4 == 0) and (n % 5 == 0)\n
True\n
"},{"location":"T2_Representation_des_donnees/2.5_Booleens/05_Operateurs_booleens/#levaluation-paresseuse","title":"L'\u00e9valuation paresseuse","text":"Pouvez-vous pr\u00e9voir le r\u00e9sultat du code ci-dessous ?
(n % 4 == 0) and (n % 0 == 0)\n
---------------------------------------------------------------------------\n\nZeroDivisionError Traceback (most recent call last)\n\n<ipython-input-3-d8a98dcba9be> in <module>\n----> 1 (n % 4 == 0) and (n % 0 == 0)\n\n\nZeroDivisionError: integer division or modulo by zero\n
\u00c9videmment, la division par 0 provoque une erreur. Mais observez maintenant ce code :
(n % 7 == 0) and (n % 0 == 0)\n
False\n
On appelle \u00e9valuation paresseuse le fait que l'interpr\u00e9teur Python s'arr\u00eate d\u00e8s que sa d\u00e9cision est prise : comme le premier bool\u00e9en vaut False et que la conjonction and
est appel\u00e9e, il n'est pas n\u00e9cessaire d'\u00e9valuer le deuxi\u00e8me bool\u00e9en.
or
C'est l'op\u00e9ration d\u00e9finie par:
C'est l'op\u00e9ration d\u00e9finie par:
x | V = V
x | F = x
On en d\u00e9duit la table suivante:
x
y
x or y
F F F F V V V F V V V V Notation usuelle en \u00e9lectronique : \\(Q=A \\vee B\\)
"},{"location":"T2_Representation_des_donnees/2.5_Booleens/05_Operateurs_booleens/#exemples-en-python_1","title":"Exemples en Python","text":"n = 20\n
(n % 10 == 0) or (n % 7 == 0)\n
True\n
(n % 4 == 0) or (n % 5 == 0)\n
True\n
(n % 7 == 0) or (n % 3 == 0)\n
False\n
"},{"location":"T2_Representation_des_donnees/2.5_Booleens/05_Operateurs_booleens/#levaluation-paresseuse-retour","title":"L'\u00e9valuation paresseuse (retour)","text":"Pouvez-vous pr\u00e9voir le r\u00e9sultat du code ci-dessous ?
(n % 5 == 0) or (n % 0 == 0)\n
"},{"location":"T2_Representation_des_donnees/2.5_Booleens/05_Operateurs_booleens/#negation-not","title":"N\u00e9gation (NOT)","text":"not
C'est l'op\u00e9ration d\u00e9finie par:
~V = F
~F = V
On en d\u00e9duit la table suivante:
x
~x
F V V F Notation usuelle en \u00e9lectronique : \\(Q=\\neg A\\)
"},{"location":"T2_Representation_des_donnees/2.5_Booleens/05_Operateurs_booleens/#exemples-en-python_2","title":"Exemples en Python","text":"n = 20\n
not(n % 10 == 0)\n
False\n
"},{"location":"T2_Representation_des_donnees/2.5_Booleens/05_Operateurs_booleens/#exercice-1","title":"Exercice 1","text":"Comprendre ce m\u00e8me.
"},{"location":"T2_Representation_des_donnees/2.5_Booleens/05_Operateurs_booleens/#exercice-2","title":"Exercice 2","text":"Exemple (inint\u00e9ressant) de circuit :
(en fran\u00e7ais OU EXCLUSIF)
x ^ y = (x & ~y) | (~x & y)
x
y
x ^ y
F F F F V V V F V V V F Le XOR joue un r\u00f4le fondamental en cryptographie car il poss\u00e8de une propri\u00e9t\u00e9 tr\u00e8s int\u00e9ressante : \\((x\\wedge y)\\wedge y=x\\)
Si \\(x\\) est un message et \\(y\\) une cl\u00e9 de chiffrage, alors \\(x\\wedge y\\) est le message chiffr\u00e9. Mais en refaisant un XOR du message chiffr\u00e9 avec la cl\u00e9 \\(y\\), on retrouve donc le message \\(x\\) initial.
"},{"location":"T2_Representation_des_donnees/2.5_Booleens/05_Operateurs_booleens/#fonction-non-et-nand","title":"Fonction Non Et (NAND)","text":"x \u2191 y = ~(x & y)
x
y
x \u2191 y
F F V F V V V F V V V F "},{"location":"T2_Representation_des_donnees/2.5_Booleens/05_Operateurs_booleens/#non-ou-nor","title":"Non Ou (NOR)","text":"x \u2193 y = ~(x & y)
x
y
x \u2193 y
F F V F V F V F F V V F Il est temps de se reposer un peu et d'admirer cette vid\u00e9o :
"},{"location":"T2_Representation_des_donnees/2.5_Booleens/05_Operateurs_booleens/#remarque","title":"Remarque :","text":"Les fonctions NAND ET NOR sont dites universelles : chacune d'entre elles peut g\u00e9n\u00e9rer l'int\u00e9gralit\u00e9 des autres portes logiques. Il est donc possible de coder toutes les op\u00e9rations uniquement avec des NAND (ou uniquement avec des NOR). Voir Wikipedia
"},{"location":"T2_Representation_des_donnees/2.5_Booleens/05_Operateurs_booleens/#exercice-4","title":"Exercice 4","text":"Calculer les op\u00e9rations suivantes.
1011011\n& 1010101\n----------\n\n\n 1011011\n| 1010101\n----------\n\n\n 1011011\n^ 1010101\n----------\n
solution
1011011\n& 1010101\n----------\n 1010001\n\n 1011011\n| 1010101\n----------\n 1011111\n\n 1011011\n^ 1010101\n----------\n 0001110\n
"},{"location":"T2_Representation_des_donnees/2.5_Booleens/05_Operateurs_booleens/#calculs-en-python","title":"Calculs en Python","text":"les op\u00e9rateurs &
, |
et ^
sont utilisables directement en Python
# calcul A\n12 & 7\n
4\n
# calcul B\n12 | 7\n
15\n
# calcul C\n12 ^ 5\n
9\n
Pour comprendre ces r\u00e9sultats, il faut travailler en binaire. Voici les m\u00eames calculs :
# calcul A\nbin(0b1100 & 0b111)\n
'0b100'\n
# calcul B\nbin(0b1100 | 0b111)\n
'0b1111'\n
# calcul C\nbin(0b1100 ^ 0b111)\n
'0b1011'\n
"},{"location":"T2_Representation_des_donnees/2.5_Booleens/05_Operateurs_booleens/#exercice-5-preparation-du-pydefi","title":"Exercice 5 : pr\u00e9paration du pyd\u00e9fi","text":"Objectif : chiffrer (= crypter) le mot \"BONJOUR\" avec la cl\u00e9 (de m\u00eame taille) \"MAURIAC\".
Protocole de chiffrage : XOR entre le code ASCII des lettres de m\u00eame position.
msg = \"BONJOUR\"\ncle = \"MAURIAC\"\n\ndef crypte_lettre(lm, lc):\n a = ord(lm)\n b = ord(lc)\n c = a^b\n lettre = chr(c)\n\n return lettre\n\ndef crypte_mot(mot1, mot2):\n mot3 = \"\"\n for i in range(len(mot1)):\n car = crypte_lettre(mot1[i],mot2[i])\n mot3 = mot3 + car\n return mot3\n\ncrypte_mot(msg, cle)\n
'\\x0f\\x0e\\x1b\\x18\\x06\\x14\\x11'\n
"},{"location":"T2_Representation_des_donnees/2.5_Booleens/05_Operateurs_booleens/#exercice-6","title":"Exercice 6 :","text":"R\u00e9solvez le pyd\u00e9fi la cl\u00e9 endommag\u00e9e
solution :
lien
"},{"location":"T2_Representation_des_donnees/2.5_Booleens/05_Operateurs_booleens/#complement-proprietes-des-operateurs-logiques","title":"Compl\u00e9ment : propri\u00e9t\u00e9s des op\u00e9rateurs logiques","text":"Les propri\u00e9t\u00e9s suivantes sont facilement d\u00e9montrables \u00e0 l'aide de tables de v\u00e9rit\u00e9s: (source : G.Connan)
Toutes ces lois sont ais\u00e9ment compr\u00e9hensibles si on les transpose en math\u00e9matiques : - & \u00e9quivaut \u00e0 \\(\\times\\) - \\(|\\) \u00e9quivaut \u00e0 \\(+\\) - \\(\\neg\\) \u00e9quivaut \u00e0 \\(-\\)
"},{"location":"T2_Representation_des_donnees/2.5_Booleens/cours/","title":"Les op\u00e9rateurs bool\u00e9ens","text":""},{"location":"T2_Representation_des_donnees/2.5_Booleens/cours/#1-reperes-historiques","title":"1. Rep\u00e8res historiques","text":"En 1847, le britannique George BOOLE inventa un formalisme permettant d'\u00e9crire des raisonnements logiques : l'alg\u00e8bre de Boole. La notion m\u00eame d'informatique n'existait pas \u00e0 l'\u00e9poque, m\u00eame si les calculs \u00e9taient d\u00e9j\u00e0 automatis\u00e9s (penser \u00e0 la Pascaline de 1642).
Bien plus tard, en 1938, les travaux de l'am\u00e9ricain Claude SHANNON prouva que des circuits \u00e9lectriques peuvent r\u00e9soudre tous les probl\u00e8mes que l'alg\u00e8bre de Boole peut elle-m\u00eame r\u00e9soudre. Pendant la deuxi\u00e8me guerre mondiale, les travaux d'Alan TURING puis de John VON NEUMANN poseront d\u00e9finitivement les bases de l'informatique moderne.
"},{"location":"T2_Representation_des_donnees/2.5_Booleens/cours/#2-algebre-de-boole","title":"2. Alg\u00e8bre de Boole","text":"L'alg\u00e8bre de Boole d\u00e9finit des op\u00e9rations dans un ensemble qui ne contient que deux \u00e9l\u00e9ments not\u00e9s 0 et 1, ou bien FAUX et VRAI ,ou encore False et True (en Python)
Les op\u00e9rations fondamentales sont :
Dans toute la suite, x
et y
d\u00e9signeront des Bool\u00e9ens (\u00e9l\u00e9ments d'une alg\u00e8bre de Boole) quelconques, F
d\u00e9signera FAUX et V
d\u00e9signera VRAI.
and
.
C'est l'op\u00e9ration d\u00e9finie par:
x & F = F
x & V = x
Puisque l'alg\u00e8bre de Boole ne contient que deux \u00e9l\u00e9ments, on peut \u00e9tudier tous les cas possibles et les regrouper dans un tableau appel\u00e9 table de v\u00e9rit\u00e9:
Table de v\u00e9rit\u00e9 de AND
x
y
x & y
F F F F V F V F F V V V On repr\u00e9sente souvent les op\u00e9rateurs bool\u00e9ens \u00e0 l'aide de portes logiques:
Notation usuelle en \u00e9lectronique : \\(Q=A \\wedge B\\)
"},{"location":"T2_Representation_des_donnees/2.5_Booleens/cours/#exemples-en-python","title":"Exemples en Python","text":">>> n = 20\n>>> (n % 10 == 0) and (n % 7 == 0)\nFalse\n>>> (n % 4 == 0) and (n % 5 == 0)\nTrue\n
"},{"location":"T2_Representation_des_donnees/2.5_Booleens/cours/#levaluation-paresseuse","title":"L'\u00e9valuation paresseuse","text":"Pouvez-vous pr\u00e9voir le r\u00e9sultat du code ci-dessous ?
>>> (n % 4 == 0) and (n % 0 == 0)\n ---------------------------------------------------------------------------\n\n ZeroDivisionError Traceback (most recent call last)\n\n <ipython-input-3-d8a98dcba9be> in <module>\n ----> 1 (n % 4 == 0) and (n % 0 == 0)\n\n\n ZeroDivisionError: integer division or modulo by zero\n
\u00c9videmment, la division par 0 provoque une erreur. Mais observez maintenant ce code :
>>> (n % 7 == 0) and (n % 0 == 0)\nFalse\n
On appelle \u00e9valuation paresseuse le fait que l'interpr\u00e9teur Python s'arr\u00eate d\u00e8s que sa d\u00e9cision est prise : comme le premier bool\u00e9en vaut False et que la conjonction and
est appel\u00e9e, il n'est pas n\u00e9cessaire d'\u00e9valuer le deuxi\u00e8me bool\u00e9en.
or
C'est l'op\u00e9ration d\u00e9finie par:
C'est l'op\u00e9ration d\u00e9finie par:
x | V = V
x | F = x
On en d\u00e9duit la table suivante:
Table de v\u00e9rit\u00e9 de OR
x
y
x or y
F F F F V V V F V V V V Notation usuelle en \u00e9lectronique : \\(Q=A \\vee B\\)
"},{"location":"T2_Representation_des_donnees/2.5_Booleens/cours/#exemples-en-python_1","title":"Exemples en Python","text":">>> n = 20\n>>> (n % 10 == 0) or (n % 7 == 0)\nTrue\n>>> (n % 4 == 0) or (n % 5 == 0)\nTrue\n>>> (n % 7 == 0) or (n % 3 == 0)\nFalse\n
"},{"location":"T2_Representation_des_donnees/2.5_Booleens/cours/#levaluation-paresseuse-retour","title":"L'\u00e9valuation paresseuse (retour)","text":"Pouvez-vous pr\u00e9voir le r\u00e9sultat du code ci-dessous ?
>>> (n % 5 == 0) or (n % 0 == 0)\n
"},{"location":"T2_Representation_des_donnees/2.5_Booleens/cours/#23-negation-not","title":"2.3 N\u00e9gation (NOT)","text":"not
C'est l'op\u00e9ration d\u00e9finie par:
~V = F
~F = V
On en d\u00e9duit la table suivante:
Table de v\u00e9rit\u00e9 de NOT
x
~x
F V V F Notation usuelle en \u00e9lectronique : \\(Q=\\neg A\\)
"},{"location":"T2_Representation_des_donnees/2.5_Booleens/cours/#exemples-en-python_2","title":"Exemples en Python","text":">>> n = 20\n>>> not(n % 10 == 0)\nFalse\n
"},{"location":"T2_Representation_des_donnees/2.5_Booleens/cours/#24-exercice-1","title":"2.4 Exercice 1","text":"Comprendre ce m\u00e8me :
"},{"location":"T2_Representation_des_donnees/2.5_Booleens/cours/#25-exercice-2","title":"2.5 Exercice 2","text":"Exercice 2
Ouvrir le simulateur de circuits et cr\u00e9er pour chaque op\u00e9ration AND, OR, NOT un circuit \u00e9lectrique illustrant ses propri\u00e9t\u00e9s.
Exemple (inint\u00e9ressant) de circuit :
"},{"location":"T2_Representation_des_donnees/2.5_Booleens/cours/#3-fonctions-composees","title":"3. Fonctions compos\u00e9es","text":""},{"location":"T2_Representation_des_donnees/2.5_Booleens/cours/#31-disjonction-exclusive-xor","title":"3.1 Disjonction exclusive XOR","text":"(en fran\u00e7ais OU EXCLUSIF)
x ^ y = (x & ~y) | (~x & y)
Table de v\u00e9rit\u00e9 de XOR
x
y
x ^ y
F F F F V V V F V V V F Le XOR joue un r\u00f4le fondamental en cryptographie car il poss\u00e8de une propri\u00e9t\u00e9 tr\u00e8s int\u00e9ressante : \\((x\\wedge y)\\wedge y=x\\)
Si \\(x\\) est un message et \\(y\\) une cl\u00e9 de chiffrage, alors \\(x\\wedge y\\) est le message chiffr\u00e9. Mais en refaisant un XOR du message chiffr\u00e9 avec la cl\u00e9 \\(y\\), on retrouve donc le message \\(x\\) initial.
"},{"location":"T2_Representation_des_donnees/2.5_Booleens/cours/#32-fonction-non-et-nand","title":"3.2 Fonction Non Et (NAND)","text":"x \u2191 y = ~(x & y)
Table de v\u00e9rit\u00e9 de NAND
x
y
x \u2191 y
F F V F V V V F V V V F "},{"location":"T2_Representation_des_donnees/2.5_Booleens/cours/#33-fonction-non-ou-nor","title":"3.3 Fonction Non Ou (NOR)","text":"x \u2193 y = ~(x & y)
Table de v\u00e9rit\u00e9 de NOR
x
y
x \u2193 y
F F V F V F V F F V V F Il est temps de se reposer un peu et d'admirer cette vid\u00e9o :
"},{"location":"T2_Representation_des_donnees/2.5_Booleens/cours/#remarque","title":"Remarque :","text":"
Les fonctions NAND ET NOR sont dites universelles : chacune d'entre elles peut g\u00e9n\u00e9rer l'int\u00e9gralit\u00e9 des autres portes logiques. Il est donc possible de coder toutes les op\u00e9rations uniquement avec des NAND (ou uniquement avec des NOR). Voir Wikipedia
"},{"location":"T2_Representation_des_donnees/2.5_Booleens/cours/#34-exercice-4","title":"3.4 Exercice 4","text":"Exercice 4
\u00c9nonc\u00e9CorrectionEffectuer les op\u00e9rations suivantes.
1011011\n& 1010101\n----------\n\n\n 1011011\n| 1010101\n----------\n\n\n 1011011\n^ 1010101\n----------\n
1011011\n&1010101\n----------\n 1010001\n\n 1011011\n|1010101\n----------\n 1011111\n\n 1011011\n^1010101\n----------\n 0001110\n
"},{"location":"T2_Representation_des_donnees/2.5_Booleens/cours/#35-calculs-en-python","title":"3.5 Calculs en Python","text":"les op\u00e9rateurs &
, |
et ^
sont utilisables directement en Python
# calcul A\n>>> 12 & 7\n4\n
# calcul B\n>>> 12 | 7\n15\n
# calcul C\n>>> 12 ^ 5\n9\n
Pour comprendre ces r\u00e9sultats, il faut travailler en binaire. Voici les m\u00eames calculs :
# calcul A\n>>> bin(0b1100 & 0b111)\n '0b100'\n
# calcul B\n>>> bin(0b1100 | 0b111)\n '0b1111'\n
# calcul C\n>>> bin(0b1100 ^ 0b111)\n '0b1011'\n
"},{"location":"T2_Representation_des_donnees/2.5_Booleens/cours/#exercice-5-cryptographie","title":"Exercice 5 : Cryptographie","text":"Exercice 5
On souhaite chiffrer (chiffrer est le mot utilis\u00e9 en cryptographie pour crypter) le mot \"BONJOUR\"
avec la cl\u00e9 \"MAURIAC\"
. Le chiffrement retenu est un chiffrement par XOR, ce qui signifie qu'on va effectuer un XOR entre les deux nombres associ\u00e9s aux lettres.
Exemple :
'B'
va \u00eatre chiffr\u00e9e gr\u00e2ce au 'M'
.'B'
est 66. (on le sait car ord('B')
renvoie 66 )'M'
est 77. (on le sait car ord('M')
renvoie 77 )'\\x0f'
(on le sait car chr(15)
renvoie '\\x0f'
)Le premier caract\u00e8re du mot chiffr\u00e9 sera donc '\\x0f'
Q1. \u00c9crire une fonction chiffre
qui prendra en param\u00e8tre un mot mot_clair
et un mot de passe cle
de m\u00eame taille que mot_clair
et qui renvoie la cha\u00eene de caract\u00e8res obtenue en XORant mot_clair
avec cle
.
Q2. Chiffrer le mot \"BONJOUR\"
avec la cl\u00e9 \"MAURIAC\"
.
Q3. Reprendre la cha\u00eene de caract\u00e8res pr\u00e9c\u00e9demment obtenue et la rechiffrer \u00e0 nouveau avec la cl\u00e9 \"MAURIAC\"
. Que constate-t-on ? Etait-ce pr\u00e9visible ?
Q4. R\u00e9soudre le Pyd\u00e9fi La cl\u00e9 endommag\u00e9e
"},{"location":"T2_Representation_des_donnees/2.5_Booleens/cours/#complement-mathematique-proprietes-des-operateurs-logiques","title":"Compl\u00e9ment math\u00e9matique: propri\u00e9t\u00e9s des op\u00e9rateurs logiques","text":"Les propri\u00e9t\u00e9s suivantes sont facilement d\u00e9montrables \u00e0 l'aide de tables de v\u00e9rit\u00e9s: (source : G.Connan)
Toutes ces lois sont ais\u00e9ment compr\u00e9hensibles si on les transpose en math\u00e9matiques :
Vous pouvez faire cette \u00e9nigme sur Capytale https://capytale2.ac-paris.fr/web/c/5912-1397991
"},{"location":"T2_Representation_des_donnees/2.5_Booleens/enonce/#1-a-la-recherche-du-personnage-mystere","title":"1. \u00c0 la recherche du personnage myst\u00e8re","text":"Vous avez trouv\u00e9 une image bien \u00e9trange :
Un visage semble se deviner derri\u00e8re un champ de fleurs... mais quel est ce visage ?
L'image du champ de fleurs ne vous est pas inconnue, d'ailleurs en cherchant bien vous l'avez retrouv\u00e9e dans vos dossiers :
On dirait que le personnage-myst\u00e8re a voulu se fondre dans le champ de fleurs...
XORez-vous d\u00e9couvrir qui est ce personnage-myst\u00e8re ?
"},{"location":"T2_Representation_des_donnees/2.5_Booleens/enonce/#2-aide-pour-la-manipulation-dimages-et-lextraction-de-pixels","title":"2. Aide pour la manipulation d'images et l'extraction de pixels","text":""},{"location":"T2_Representation_des_donnees/2.5_Booleens/enonce/#21-code-de-demarrage","title":"2.1 Code de d\u00e9marrage","text":"from PIL import Image\n\nimg_myst = Image.open(\"mystere.bmp\")\nimg_mask = Image.open(\"mask.jpg\")\n\nlargeur = img_myst.width\nhauteur = img_myst.height\n\nimg_new = Image.new('RGB', img_myst.size)\n
"},{"location":"T2_Representation_des_donnees/2.5_Booleens/enonce/#22-manipulation-de-pixels","title":"2.2 Manipulation de pixels","text":"Les expressions ci-dessous sont \u00e0 tester pour en comprendre le fonctionnement.
"},{"location":"T2_Representation_des_donnees/2.5_Booleens/enonce/#221-recuperer-le-code-rgb-un-pixel","title":"2.2.1 R\u00e9cup\u00e9rer le codeRGB
un pixel","text":">>> img_myst.getpixel((125, 80))\n(54, 217, 174)\n
Le pixel de coordonn\u00e9es (125, 80) a pour composantes RGB (54, 217, 174)."},{"location":"T2_Representation_des_donnees/2.5_Booleens/enonce/#222-modifier-la-couleur-dun-pixel","title":"2.2.2 Modifier la couleur d'un pixel","text":">>> img_new.putpixel((30,70), (255,0,0))\n>>> \n
Le pixel de coordonn\u00e9es (30, 70) est maintenant un pixel rouge."},{"location":"T2_Representation_des_donnees/2.5_Booleens/enonce/#223-afficher-une-image","title":"2.2.3 Afficher une image","text":">>> img_mask.show()\n
"},{"location":"T2_Representation_des_donnees/2.5_Booleens/enonce/#224-sauvegarder-une-image","title":"2.2.4 Sauvegarder une image","text":">>> img_new.save(\"solution.png\")\n
"},{"location":"T2_Representation_des_donnees/2.6_Codage_caracteres/cours/","title":"2.6 Codage des caract\u00e8res","text":"Tout pour comprendre et \u00c3\u00a9viter les erreurs d'encodage
"},{"location":"T2_Representation_des_donnees/2.6_Codage_caracteres/cours/#1-au-commencement-etait-lascii","title":"1. Au commencement \u00e9tait l'ASCII","text":"pour American Standard Code for Information Interchange, cr\u00e9\u00e9 en 1960 aux \u00c9tats-Unis.
En ASCII, 127 \u00abpoints de code\u00bb (nombres associ\u00e9s aux caract\u00e8res) sont disponibles. Les caract\u00e8res sont donc cod\u00e9s sur 7 bits.
Exercice
\u00c9nonc\u00e9AideCorrectionD\u00e9coder l'expression suivante, \u00e9crite en ASCII :
1101100 1100101 1110011 100000 1001110 1010011 1001001 100000 1100011 100111 1100101 1110011 1110100 100000 1101100 1100101 1110011 100000 1101101 1100101 1101001 1101100 1101100 1100101 1110101 1110010 1110011
split(\" \")
permet de d\u00e9composer une chaine de caract\u00e8res en une liste, en se servant de l'espace \" \"
comme caract\u00e8re s\u00e9parateur.int(\"1101100\",2)
permet de r\u00e9cup\u00e9rer facilement la valeur en base 10 du nombre binaire 1101100
.msg = \"1101100 1100101 1110011 100000 1001110 1010011 1001001 100000 1100011 100111 1100101 1110011 1110100 100000 1101100 1100101 1110011 100000 1101101 1100101 1101001 1101100 1101100 1100101 1110101 1110010 1110011\"\nmsg = msg.split(' ')\ns = \"\"\nfor k in msg :\n s += chr(int(k,2))\nprint(s)\n
"},{"location":"T2_Representation_des_donnees/2.6_Codage_caracteres/cours/#2-et-le-reste-du-monde","title":"2. Et le reste du monde ?","text":"Lorsque d'autres personnes que des americains ou des anglais ont voulu s'\u00e9changer des donn\u00e9es faisant intervenir du texte, certains caract\u00e8res (\u00e9, \u00e8, \u00e0, \u00f1, \u00d8, \u00d6, \u03b2, \u6f22...) \u00e9taient manquants. Les 127 caract\u00e8res de l'ASCII \u00e9taient largement insuffisants. Il a donc \u00e9t\u00e9 d\u00e9cid\u00e9 de passer \u00e0... 256 caract\u00e8res ! Il suffisait pour cela de coder les caract\u00e8res non plus sur 7 bits mais sur 8 bits.
Ainsi naqu\u00eet, apr\u00e8s de nombreuses modifications successives (la derni\u00e8re en date rajoutant par exemple le symbole \u20ac), la c\u00e9l\u00e8bre table ISO 8859-15, dite aussi Latin-9 :
"},{"location":"T2_Representation_des_donnees/2.6_Codage_caracteres/cours/#utilisation","title":"Utilisation :","text":"Les codes sont donn\u00e9s en hexad\u00e9cimal :
65... comme en ASCII ! Oui, la (seule) bonne id\u00e9e aura \u00e9t\u00e9 d'inclure les caract\u00e8res ASCII avec leur m\u00eame code, ce qui rendait cette nouvelle norme r\u00e9tro-compatible.
Exemple :
Le fichier test.txt
contient un texte enregistr\u00e9 avec l'encodage Latin-9. Ce fichier est ensuite ouvert avec un \u00e9diteur hexad\u00e9cimal, qui permet d'observer la valeur des octets qui composent le fichier. (Comme le fichier est un .txt, le fichier ne contient que les donn\u00e9es et rien d'autre.)
Parfait, mais comment font les Grecs pour \u00e9crire leur alphabet ? Pas de probl\u00e8me, il leur suffit d'utiliser... une autre table, appel\u00e9e ISO-8859-7 :
On retrouve les caract\u00e8res universels h\u00e9rit\u00e9s de l'ASCII, puis des caract\u00e8res sp\u00e9cifiques \u00e0 la langue grecque... oui mais les Tha\u00eflandais alors ?
Pas de probl\u00e8me, ils ont la ISO-8859-11 :
\u00c9videmment, quand tous ces gens veulent discuter entre eux, les probl\u00e8mes d'encodage surviennent imm\u00e9diatement : certains caract\u00e8res sont remplac\u00e9s par d'autres.
"},{"location":"T2_Representation_des_donnees/2.6_Codage_caracteres/cours/#3-que-fait-un-logiciel-a-louverture-dun-fichier-texte","title":"3. Que fait un logiciel \u00e0 l'ouverture d'un fichier texte ?","text":"Il essaie de deviner l'encodage utilis\u00e9... Parfois cela marche, parfois non.
Normalement, pour un navigateur, une page web correctement cod\u00e9e doit contenir dans une balise meta
le charset
utilis\u00e9.
Mais parfois, il n'y a pas d'autre choix pour le logiciel d'essayer de deviner l'encodage qui semble \u00eatre utilis\u00e9.
Exercice
\u00c9nonc\u00e9CorrectionLe mot repr\u00e9sent\u00e9 par les octets ci-dessous est-il encod\u00e9 en ASCII ou en Latin-9 ?
C'est du Latin-9, et c'est le mot \"v\u00e9lo\"
"},{"location":"T2_Representation_des_donnees/2.6_Codage_caracteres/cours/#4-enfin-une-normalisation-larrivee-de-lutf","title":"4. Enfin une normalisation : l'arriv\u00e9e de l'UTF","text":"En 1996, le Consortium Unicode d\u00e9cide de normaliser tout cela et de cr\u00e9er un syst\u00e8me unique qui contiendra l'int\u00e9gralit\u00e9 des caract\u00e8res dont les \u00eatres humains ont besoin pour communiquer entre eux.
Ils cr\u00e9ent l'Universal character set Transformation Format : l'UTF. Ou plut\u00f4t ils en cr\u00e9ent... plusieurs :
Pourquoi est-ce encore si compliqu\u00e9 ? En UTF-32, 32 bits sont disponibles, soit \\(2^{32}=4294967296\\) caract\u00e8res diff\u00e9rents encodables.
C'est largement suffisant, mais c'est surtout tr\u00e8s tr\u00e8s lourd ! D'autres encodages plus l\u00e9gers, mais plus complexes, sont donc propos\u00e9s :
Arr\u00eatons-nous sur l'UTF-8 :
Le principe fondateur de l'UTF-8 est qu'il est adaptatif : les carac\u00e8res les plus fr\u00e9quents sont cod\u00e9s sur un octet, qui est la taille minimale (et qui donne le 8 de \"UTF-8\"). Les autres caract\u00e8res peuvent \u00eatre cod\u00e9s sur 2, 3 ou 4 octets au maximum.
"},{"location":"T2_Representation_des_donnees/2.6_Codage_caracteres/cours/#5-la-reponse-a-une-question-existentielle","title":"5. La r\u00e9ponse \u00e0 une question existentielle","text":"Pourquoi le caract\u00e8re \u00e9
en UTF-8 devient-il \u00c3\u00a9
en ISO 8859-15 ?
Q1. Gr\u00e2ce \u00e0 la fonction ord
puis \u00e0 la fonction bin
, \u00e9crire en binaire le nombre associ\u00e9 au caract\u00e8re \u00e9
en UTF-8.
>>> ord('\u00e9')\n233\n>>> bin(233)\n'0b11101001'\n
Donc en UTF-8, \u00e9
est associ\u00e9 au nombre 11101001
. Q2. D'apr\u00e8s l'explication de fonctionnement de l'encodage adaptatif de l'UTF-8 (voir ci-dessus), les 8 bits n\u00e9cessaires \u00e0 l'encodage de \u00e9
en UTF-8 vont \u00eatre \u00abencapsul\u00e9s\u00bb dans 2 octets de la forme 110XXXXX 10XXXXXX
, o\u00f9 les 11 X
repr\u00e9sentent les 11 bits d'information disponibles. \u00c9crire ces 2 octets en compl\u00e9tant si n\u00e9cessaire avec des 0
\u00e0 gauche.
Sur 11 bits, le nombre 11101001
va s'\u00e9crire 00011101001
. En s\u00e9parant ces 11 bits en deux groupes de 5 bits et 6 bits (00011
et 101001
), et en les encapsulant, on obtient les deux octets 11000011 10101001
.
Q3. Convertir les deux octets obtenus en notation d\u00e9cimale (gr\u00e2ce \u00e0 int
) puis en hexad\u00e9cimal (gr\u00e2ce \u00e0 hex
).
>>> int('11000011', 2)\n195\n>>> hex(195)\n'0xc3'\n>>> int('10101001', 2)\n169\n>>> hex(169)\n'0xa9'\n
Q4. Si un logiciel consid\u00e8re \u00e0 tort que les deux octets servant \u00e0 encoder le \u00e9
en UTF-8 servent \u00e0 encoder deux caract\u00e8res en ISO 8859-15, quels seront ces deux caract\u00e8res ?
Le premier octet, c3
en hexad\u00e9cimal, sera per\u00e7u en ISO 8859-15 comme le caract\u00e8re \u00c3
. Le deuxi\u00e8me octet, a9
en hexad\u00e9cimal, sera per\u00e7u en ISO 8859-15 comme la lettre \u00a9
.
Finalement, ce qui aurait d\u00fb \u00eatre un \u00e9
en UTF-8 se retrouvera \u00eatre un \u00c3\u00a9
en ISO 8859-15.
La majorit\u00e9 des sites internet utilisent maintenant l'UTF-8, tout comme les syst\u00e8mes d'exploitation r\u00e9cents.
"},{"location":"T2_Representation_des_donnees/2.7_Codage_entiers/cours/","title":"2.7 Codage des entiers","text":"Attention
La mani\u00e8re dont les nombres (entiers, non-entiers, positifs, n\u00e9gatifs...) sont trait\u00e9s par un langage de programmation est sp\u00e9cifique \u00e0 ce langage.
Dans toute la suite de ce cours, pour simplifier, nous consid\u00e9rerons que les nombres sont cod\u00e9s sur 1 octet seulement. Ce qui ne correspond pas \u00e0 la r\u00e9alit\u00e9, mais permet de comprendre les notions essentielles.
"},{"location":"T2_Representation_des_donnees/2.7_Codage_entiers/cours/#1-les-nombres-entiers-en-binaire-non-signe","title":"1. Les nombres entiers en binaire non sign\u00e9","text":"L'expression \"non sign\u00e9\" signifie que la contrainte du signe n'existe pas : tous les nombres sont consid\u00e9r\u00e9s comme \u00e9tant positifs.
Nous avons d\u00e9j\u00e0 vu comment ces nombres se codaient en binaire.
Sur un octet, le nombre minimal qu'on puisse coder est 00000000
. C'est l'entier naturel 0. Le nombre maximal qu'on puisse coder est 11111111
. C'est l'entier naturel 255.
Exercice
\u00c9nonc\u00e9CorrectionPython et les entiers
Depuis la version 3 du langage Python, il n'y a plus de taille maximale pour les entiers en Python.
Ceci implique que la taille n\u00e9cessaire au codage de l'entier est allou\u00e9e dynamiquement par Python (avec pour seule limite celle de la m\u00e9moire disponible).
Exercice
\u00c9nonc\u00e9Correction00001101
et 00001011
.Comment diff\u00e9rencier les nombres positifs des nombres n\u00e9gatifs ? L'id\u00e9e naturelle est de r\u00e9server 1 bit pour le signe, et de coder le reste du nombre \u00abnaturellement\u00bb.
Par exemple, on peut d\u00e9cr\u00e9ter que le premier bit (appel\u00e9 bit de poids fort) sera le bit de signe :
Dans ce cas, 00000011
serait le nombre \\(+3\\) et 10000011
serait le nombre \\(-3\\).
Probl\u00e8mes :
00000000
et 10000000
, ce qui n'est pas tr\u00e8s \u00e9conome.Moralit\u00e9 :
Ce syst\u00e8me d'\u00e9criture ne marche pas bien.
"},{"location":"T2_Representation_des_donnees/2.7_Codage_entiers/cours/#22-a-la-recherche-de-loppose-dun-nombre","title":"2.2 \u00c0 la recherche de l'oppos\u00e9 d'un nombre","text":"Id\u00e9e :
Plut\u00f4t que de chercher \u00e0 \u00e9crire directement le nombre \\(-3\\), nous allons chercher \u00e0 d\u00e9terminer ce qu'il faut ajouter \u00e0 \\((+3)\\) pour obtenir 0.
Que faut-il ajouter au nombre \\((+3)\\) pour obtenir 0 ?
L'id\u00e9e naturelle est de commencer par la droite, en essayant de \u00abfabriquer du z\u00e9ro\u00bb en choisissant le bon bit \u00e0 ajouter :
On arrive bien \u00e0 fabriquer des 0 sur tout notre octet, mais que devient la retenue (en anglais carry) de 1 qui d\u00e9borde de notre octet ?
R\u00e9ponse : rien ! Elle sera perdue et c'est une tr\u00e8s bonne nouvelle. Ce nombre sera donc consid\u00e9r\u00e9 comme un 0 : nous avons trouv\u00e9 comment coder \\(-3\\).
Le nombre \\(-3\\) s'\u00e9crit donc 11111101
.
Comment, \u00e0 partir du nombre 00000011
, aurait-on pu le trouver directement (sans raisonner de proche en proche) ?
On peut remarquer qu'en inversant chaque bit du nombre de d\u00e9part 00000011
, on obtient 11111100
, qui appel\u00e9 le compl\u00e9ment \u00e0 2 du nombre 00000011
.
Il ne reste donc plus qu'\u00e0 ajouter 1
\u00e0 ce nombre 11111100
pour obtenir le nombre cherch\u00e9, 11111101
ce nombre 11111101
repr\u00e9sente 253 en codage non sign\u00e9. Il est donc n\u00e9cessaire, lorsqu'on repr\u00e9sente un nombre, de savoir si les nombres manipul\u00e9s seront des entiers naturels (non sign\u00e9s) ou bien relatifs (sign\u00e9s).
Consid\u00e9rons que ce nombre positif s'\u00e9crit sur 7 bits, donc qu'il est de la forme 0XXXXXXX
.
\u00c9criture de l'oppos\u00e9 d'un nombre positif
Exercice
\u00c9nonc\u00e9CorrectionDonner l'\u00e9criture binaire sur un octet du nombre \\(-13\\).
Commen\u00e7ons par \u00e9crire le nombre 13 en binaire. Il s'\u00e9crit \u00a000001101
.
11110010
.11110011
. Le nombre \\(-13\\) s'\u00e9crit donc 11110011
.
Remarque Les nombres n\u00e9gatifs commenceront donc toujours par le bit 1, et les nombres positifs par le bit 0. Cela revient \u00e0 suivre partiellement notre fausse bonne id\u00e9e du 2.1. Et cela donne surtout une m\u00e9thode tr\u00e8s pratique pour savoir qui est positif et qui est n\u00e9gatif !
"},{"location":"T2_Representation_des_donnees/2.7_Codage_entiers/cours/#3-travail-inverse-passage-du-binaire-signe-au-nombre-relatif","title":"3. Travail inverse : passage du binaire sign\u00e9 au nombre relatif","text":"Consid\u00e9rons le nombre 11101101
, cod\u00e9 en binaire sign\u00e9. \u00c0 quel nombre relatif correspond-il ?
11101100
.00010011
.Exercice
\u00c9nonc\u00e9Correction11110001
?11110001
- 1
= 11110000
. En prenant le compl\u00e9ment \u00e0 2, on trouve 00001111
, qui vaut 15. Le nombre 11110001
repr\u00e9sente donc \\(-15\\).01111111
, soit \\(+127\\).10000000
. 10000000
- 1
= 01111111
. Le compl\u00e9ment est 10000000
, qui est \u00e9gal \u00e0 128. Donc le nombre minimal est \\(-128\\).Le 04 juin 1996, le vol inaugural d'Ariane 5 a malheureusement fini dans une gerbe d'\u00e9tincelles.
En cause : un code pr\u00e9vu pour Ariane 4 avait \u00e9t\u00e9 gard\u00e9 pour le nouveau mod\u00e8le Ariane 5. Dans ce \u00abvieux\u00bb code, une donn\u00e9e issue d'un capteur (le capteur de vitesse horizontale) \u00e9tait cod\u00e9 sur 8 bits. La valeur maximale acceptable de cette donn\u00e9e \u00e9tait donc 255.
Or, Ariane 5 \u00e9tant beaucoup plus puissante, le capteur de vitesse horizontale a renvoy\u00e9, au bout de 30 secondes, la valeur 300 : cette valeur a provoqu\u00e9 un d\u00e9passement des 8 bits pr\u00e9vus et a donn\u00e9 un r\u00e9sultat absurde. L'ordinateur de bord a cru que la fus\u00e9e \u00e9tait en train de se coucher et a violemment orient\u00e9 les tuy\u00e8res de propulsion pour redresser Ariane 5, alors que celle-ci s'\u00e9levait pourtant bien verticalement... Ariane 5 a alors brusquement pivot\u00e9 avant d'exploser.
Cette catastrophe (150 millions d'euros et des ann\u00e9es de travail perdus) a fait prendre conscience \u00e0 la communaut\u00e9 scientifique de l'importance de faire des tests logiciels toujours plus pouss\u00e9s : ce n'est pas parce qu'un code marche dans un environnement donn\u00e9 qu'il marchera de la m\u00eame mani\u00e8re dans d'autres conditions...
"},{"location":"T2_Representation_des_donnees/2.7_Codage_entiers/cours/#42-le-bug-de-lannee-2038","title":"4.2 Le bug de l'ann\u00e9e 2038","text":"Expliquons ce (superbe) gif issu de la page Wikipedia Bug de l'an 2038.
Lorsqu'on demande \u00e0 Python l'heure qu'il est, par la fonction time()
du module time
, voici ce qu'il r\u00e9pond :
>>> import time\n>>> time.time()\n1653855138.398177\n
Il nous renvoie le nombre de secondes \u00e9coul\u00e9es depuis le 1er janvier 1970 \u00e0 00h00. On appelle cela l'heure POSIX ou l'heure UNIX l'heure UNIX. Au 29 mai 2022, il s'en donc \u00e9coul\u00e9 environ 1,6 milliards.
Dans beaucoup de syst\u00e8mes informatiques, ce nombre de secondes est cod\u00e9 par un entier sign\u00e9 sur 32 bits. Le nombre maximum de secondes qui peut \u00eatre repr\u00e9sent\u00e9 est donc 01111111 11111111 11111111 11111111
>>> int('01111111111111111111111111111111', 2)\n2147483647\n
Ce nombre repr\u00e9sente un peu plus de 2 milliards de secondes... En les comptant depuis le 01/01/1970 00h00m00s, on arrive au 19/01/2038 \u00e0 03h14m07s.
\u00c0 la seconde d'apr\u00e8s, la repres\u00e9ntation binaire du temps sera 10000000 00000000 00000000 00000000
, qui sera interpr\u00e9t\u00e9 comme le nombre n\u00e9gatif \u22122147483648, et qui ram\u00e8nera donc les horloges au 13 d\u00e9cembre 1901...
Vous pourrez lire sur la page Wikipedia cit\u00e9e plus haut plus d'informations sur ce probl\u00e8me.
"},{"location":"T2_Representation_des_donnees/2.8_Codage_non-entiers/cours/","title":"2.8 Codage des non-entiers","text":"Le principe est l'extension du syst\u00e8me d\u00e9j\u00e0 rencontr\u00e9 pour les nombres entiers. La partie d\u00e9cimale (\u00e0 droite de la virgule) correspondra aux puissances n\u00e9gatives de 2.
... 8 4 2 1 0.5 0.25 0.125 ... ... \\(2^3\\) \\(2^2\\) \\(2^1\\) \\(2^0\\) \\(2^{-1}\\) \\(2^{-2}\\) \\(2^{-3}\\) ... ... 0 1 1 0, 1 0 1 ...Exemple : \\(110,101_2=1 \\times 2^2 + 1 \\times2^1 +0 \\times 2^0 + 1 \\times 2^{-1} +0 \\times 2^{-2}+1 \\times 2^{-2} =4+2+0,5+0,125=6,625\\)
"},{"location":"T2_Representation_des_donnees/2.8_Codage_non-entiers/cours/#1-tentatives-de-conversion","title":"1. Tentatives de conversion","text":""},{"location":"T2_Representation_des_donnees/2.8_Codage_non-entiers/cours/#11-theoreme-de-decomposition-en-puissances-de-2","title":"1.1 Th\u00e9or\u00e8me de d\u00e9composition en puissances de 2","text":"Tout commence bien, avec un r\u00e9sultat math\u00e9matique rassurant : tous les nombres r\u00e9els peuvent s'\u00e9crire comme une somme de puissances de 2 (puissances positives et n\u00e9gatives).
Th\u00e9or\u00e8me
Pour tout r\u00e9el \\(x \\in \\mathbb{R}^+\\), il existe \\(p \\in \\mathbb{N}\\) et \\((a_p,a_{p-1},...,a_0,a_{-1},a_{-2},...)\\) tels que \\(x = \\sum_{i=0}^pa_i2^i+\\sum_{i=1}^{+\\infty}a_{-i}2^{-i}\\)
\u00c9crire un nombre en binaire revient \u00e0 calculer les coefficients \\(a_k\\) (ils sont \u00e9gaux \u00e0 0 ou 1). Il y en a un nombre fini pour la partie enti\u00e8re, mais un nombre potentiellement infini pour la partie d\u00e9cimale.
"},{"location":"T2_Representation_des_donnees/2.8_Codage_non-entiers/cours/#12-methode-de-conversion","title":"1.2 M\u00e9thode de conversion","text":"Consid\u00e9rons le nombre \\(3,6875\\). Il se d\u00e9compose en une partie enti\u00e8re (3) et une partie d\u00e9cimale (\\(0,6875\\)).
On prend ensuite le chiffre des unit\u00e9s de tous les nombres obtenus : 1011
Donc \\(3,6875=11,1011_2\\)
Exercice 1
\u00c9nonc\u00e9CorrectionDonner l'\u00e9criture binaire de 20,875.
Donc \\(20,875=10100,111_2\\)
Exercice 2
\u00c9nonc\u00e9CorrectionDonner l'\u00e9criture binaire de 0,2.
Le nombre 0,2 n'admet pas d'\u00e9criture binaire finie.
"},{"location":"T2_Representation_des_donnees/2.8_Codage_non-entiers/cours/#conclusion","title":"Conclusion","text":"Certains nombres n'admettent pas une \u00e9criture binaire finie. Or la m\u00e9moire d'un ordinateur, quelqu'il soit, est toujours finie. Certains nombres ne peuvent donc pas \u00eatre repr\u00e9sent\u00e9s correctement en machine : c'est une impossibilit\u00e9 th\u00e9orique. Cela am\u00e8ne \u00e0 des comportements \u00e9tranges :
>>> 0.1 + 0.2\n0.30000000000000004\n
Remarque : parmi les nombres d\u00e9cimaux \u00e0 un chiffre apr\u00e8s la virgule (0,1 0,2 0,3 ...) seul 0,5 admet une \u00e9criture binaire finie ! Tous les autres ont une repr\u00e9sentation en machine qui n'en donne qu'une valeur approch\u00e9e.
"},{"location":"T2_Representation_des_donnees/2.8_Codage_non-entiers/cours/#2-consequences-la-difficile-manipulation-des-flottants","title":"2. Cons\u00e9quences : la difficile manipulation des flottants","text":"En python, les nombres non entiers sont du type float.
>>> type(0.1)\n<class 'float'>\n
Ces flottants (traduction fran\u00e7aise) sont \u00e0 manipuler avec une extr\u00eame pr\u00e9caution. Il faut garder en t\u00eate que les calculs sont potentiellement faux, du moins impr\u00e9cis, lorsque des flottants interviennent.
>>> 0.5-0.2-0.2-0.1\n-2.7755575615628914e-17\n
En 1991, durant la Guerre du Golfe, un missile anti-missile am\u00e9ricain a rat\u00e9 sa cible de 500 m\u00e8tres car son ordinateur interne \u00e9mettait un signal toutes les 0.1 secondes. Au bout de 100 heures de fonctionnement, l'approximation du nombre flottant 0.1 a conduit \u00e0 un d\u00e9calage de 0,34 secondes, ce qui lui a fait rater sa cible. (source)
"},{"location":"T2_Representation_des_donnees/2.8_Codage_non-entiers/cours/#3-comment-faire-des-tests-degalite-sur-les-flottants","title":"3. Comment faire des tests d'egalit\u00e9 sur les flottants ?","text":"Premi\u00e8re r\u00e9ponse : ON N'EN FAIT PAS.
Si a
et b
sont deux flottants, le test classique
if a == b :\n print(\"a et b sont \u00e9gaux\")\n
a de grandes chances d'\u00e9chouer :
Le script
a = 0.1\nb = 0.3 - 0.2\nif a == b :\n print(\"a et b sont \u00e9gaux\")\nelse :\n print(\"a et b sont diff\u00e9rents\")\n
renverra
a et b sont diff\u00e9rents\n
Si vraiment un test d'\u00e9galit\u00e9 est n\u00e9cessaire, on ne va pas tester l'\u00e9galit\u00e9 entre a
et b
mais leur proximit\u00e9, gr\u00e2ce \u00e0 la valeur absolue de leur diff\u00e9rence.
La fonction abs(a-b)
renvoie un nombre positif \u00e9gal \u00e0 la distance entre a
et b
. Il faut alors d\u00e9cider d'un \u00e9cart minimal e
en dessous duquel on consid\u00e8rera que a
et b
sont \u00e9gaux.
Le script
a = 0.1\nb = 0.3-0.2\ne = 10**(-12)\nif abs(a-b) < e :\n print(\"a et b sont \u00e9gaux\")\nelse :\n print(\"a et b sont diff\u00e9rents\")\n
renverra
a et b sont \u00e9gaux\n
Exercice
\u00c9nonc\u00e9CorrectionOn consid\u00e8re la fonction \\(f(x)=x^3-6x+2\\). L'\u00e9quation \\(f(x)=1\\) admet une solution unique dans l'intervalle \\([0;1]\\). Trouver une valeur approch\u00e9e de cette solution \u00e0 \\(10^{-5}\\) pr\u00e8s. On prendra e
\\(=0,001\\).
def f(x):\n return x**3 - 6 * x + 2\n\ne = 10**(-3)\na = 0\nwhile abs(f(a) - 1 ) > e :\n a += 10**(-5)\nprint(a)\n
"},{"location":"T2_Representation_des_donnees/2.9_Chaines_caracteres/cours/","title":"2.9 Cha\u00eenes de caract\u00e8res","text":"La manipulation des cha\u00eenes de caract\u00e8res n'est pas au programme, mais quelques astuces sont tr\u00e8s utiles \u00e0 conna\u00eetre.
"},{"location":"T3_Architecture_materielle/sommaire/","title":"Th\u00e8me 3 : Architecture mat\u00e9rielle","text":"BBC micro:bit est une carte \u00e0 microcontr\u00f4leur con\u00e7ue en 2015 au Royaume-Uni pour d\u00e9velopper l'apprentissage de l'algorithmique et de la programmation.
La carte micro:bit dispose des sp\u00e9cificit\u00e9s techniques suivantes :
Rendez-vous sur la page https://create.withcode.uk/
Effacez le code existant et collez-le code ci-dessous :
from microbit import *\n\nwhile True:\n display.scroll('Hello, World!')\n display.show(Image.HEART)\n sleep(2000)\n
Cliquez sur le triangle vert en bas \u00e0 droite. C'est parti !
Pour \u00e9viter des erreurs, fermez la fen\u00eatre de droite (le simulateur) \u00e0 chaque fois que vous modifiez votre code de la partie gauche.
"},{"location":"T3_Architecture_materielle/3.1_Microbit/cours/#12-avec-une-microbit-reelle","title":"1.2 Avec une micro:bit r\u00e9elle","text":"Cette proc\u00e9dure est \u00e0 r\u00e9peter \u00e0 chaque nouveau code.
"},{"location":"T3_Architecture_materielle/3.1_Microbit/cours/#2-decouverte-des-fonctionnalites","title":"2. D\u00e9couverte des fonctionnalit\u00e9s","text":""},{"location":"T3_Architecture_materielle/3.1_Microbit/cours/#21-commandes-de-base-de-lafficheur-matrice-de-5x5-leds","title":"2.1 Commandes de base de l'afficheur, matrice de 5x5 LEDs","text":"voir vid\u00e9o explicative (en anglais)
LED signifie Light Emitting Diode, Diode \u00e9lectroluminescente. La carte micro:bit en dispose de 25, toutes programmables individuellement, ce qui permet d'afficher du texte, des nombres et des images.
"},{"location":"T3_Architecture_materielle/3.1_Microbit/cours/#211-afficher-un-texte-defilant-displayscrollstring-delay400","title":"2.1.1 Afficher un texte \"d\u00e9filant\"display.scroll(string, delay=400)
","text":"from microbit import *\ndisplay.scroll(\"NSI\")\n
La premi\u00e8re ligne de ce programme importe la biblioth\u00e8que de fonctions micro:bit. La deuxi\u00e8me ligne fait d\u00e9filer un message \u00e0 l\u2019\u00e9cran. Cela n'arrive qu'une seule fois.
La vitesse de d\u00e9filement peut \u00eatre ralentie ou acc\u00e9l\u00e9r\u00e9e \u00e0 l'aide du param\u00e8tre delay
. L'unit\u00e9 est la milliseconde.
from microbit import *\ndisplay.scroll(\"mauriac\", delay=20)\n
"},{"location":"T3_Architecture_materielle/3.1_Microbit/cours/#212-afficher-une-image-displayshowimage","title":"2.1.2 Afficher une \"image\" display.show(image)
","text":"Ex\u00e9cuter le programme suivant:
from microbit import *\ndisplay.show(Image.SAD)\n
Liste des images disponibles Image.HEART\nImage.HEART_SMALL\nImage.HAPPY\nImage.SMILE\nImage.SAD\nImage.CONFUSED\nImage.ANGRY\nImage.ASLEEP\nImage.SURPRISED\nImage.SILLY\nImage.FABULOUS\nImage.MEH\nImage.YES\nImage.NO\nImage.CLOCK12\nImage.CLOCK11\nImage.CLOCK10\nImage.CLOCK9\nImage.CLOCK8\nImage.CLOCK7\nImage.CLOCK6\nImage.CLOCK5\nImage.CLOCK4\nImage.CLOCK3\nImage.CLOCK2\nImage.CLOCK1\nImage.ARROW_N\nImage.ARROW_NE\nImage.ARROW_E\nImage.ARROW_SE\nImage.ARROW_S\nImage.ARROW_SW\nImage.ARROW_W\nImage.ARROW_NW\nImage.TRIANGLE\nImage.TRIANGLE_LEFT\nImage.CHESSBOARD\nImage.DIAMOND\nImage.DIAMOND_SMALL\nImage.SQUARE\nImage.SQUARE_SMALL\nImage.RABBIT\nImage.COW\nImage.MUSIC_CROTCHET\nImage.MUSIC_QUAVER\nImage.MUSIC_QUAVERS\nImage.PITCHFORK\nImage.XMAS\nImage.PACMAN\nImage.TARGET\nImage.TSHIRT\nImage.ROLLERSKATE\nImage.DUCK\nImage.HOUSE\nImage.TORTOISE\nImage.BUTTERFLY\nImage.STICKFIGURE\nImage.GHOST\nImage.SWORD\nImage.GIRAFFE\nImage.SKULL\nImage.UMBRELLA\nImage.SNAKE\n
"},{"location":"T3_Architecture_materielle/3.1_Microbit/cours/#creer-sa-propre-image","title":"Cr\u00e9er sa propre image","text":"Chaque pixel LED sur l\u2019affichage physique peut prendre une parmi dix valeurs. Si un pixel prend la valeur 0 c\u2019est qu\u2019il est \u00e9teint. Litt\u00e9ralement, il a une luminosit\u00e9 de z\u00e9ro. En revanche, s\u2019il prend la valeur 9 il est \u00e0 la luminosit\u00e9 maximale. Les valeurs de 1 \u00e0 8 repr\u00e9sentent des niveaux de luminosit\u00e9 entre \u00e9teint (0) et \u00ab au maximum \u00bb (9).
from microbit import *\n\nbateau = Image(\"05050:\"\n \"05050:\"\n \"05050:\"\n \"99999:\"\n \"09990\")\n\ndisplay.show(bateau)\n
Comment dessiner une image? Chaque ligne de l\u2019affichage physique est repr\u00e9sent\u00e9e par une ligne de nombres se terminant par :
et entour\u00e9e de guillemets doubles \"
. Chaque nombre indique une luminosit\u00e9. Il y a cinq lignes de cinq nombres donc il est possible de sp\u00e9cifier la luminosit\u00e9 individuelle de chacune des cinq LED sur chacune des cinq lignes sur l\u2019affichage physique. C\u2019est ainsi que l'on cr\u00e9e une image.
display.set_pixel(x, y, val)
)","text":"Vous pouvez r\u00e9gler la luminosit\u00e9 des pixels de l'affichage individuellement de 0 (d\u00e9sactiv\u00e9) \u00e0 9 (luminosit\u00e9 maximale). Pour des informations sur les coordonn\u00e9es de l'affichage, voir le guide pour matrice \u00e0 LED.
Ex\u00e9cuter le programme suivant:
from microbit import *\ndisplay.set_pixel(1, 4, 9)\n
"},{"location":"T3_Architecture_materielle/3.1_Microbit/cours/#22-boucle-while","title":"2.2 Boucle while
","text":"Le programme suivant utilise une boucle while
pour faire clignoter le pixel central de mani\u00e8re r\u00e9p\u00e9t\u00e9e sur l\u2019\u00e9cran. La boucle while
se r\u00e9p\u00e8te tant que la condition sp\u00e9cifi\u00e9e est vraie (True
). Dans ce cas, nous avons dit que la condition est vraie. Cela cr\u00e9e une boucle infinie.
L'instruction de veille sleep()
provoque la pause du micro:bit pendant un nombre d\u00e9fini de millisecondes choisi entre parenth\u00e8ses.
L'instruction display.clear()
\u00e9teint l'affichage.
Ex\u00e9cuter le programme ci-dessous:
from microbit import *\nwhile True:\n display.set_pixel(2, 2, 9)\n sleep(500)\n display.clear()\n sleep(500)\n
"},{"location":"T3_Architecture_materielle/3.1_Microbit/cours/#avec-un-peu-daleatoire-voir-documentation-sur-le-hasard","title":"Avec un peu d'al\u00e9atoire (voir documentation sur le hasard)","text":"Dans le programme suivant que vous ex\u00e9cuterez, on importe randint
du module random
de MicroPython et on l'utilise pour afficher un pixel au hasard sur la matrice.
from microbit import *\nfrom random import randint\nn=randint(0,4)\np=randint(0,4)\ndisplay.set_pixel(n, p, 9)\n
Tester le programme pr\u00e9c\u00e9dent plusieurs fois de suite. Pour cela, red\u00e9marrer la micro:bit en appuyant sur le bouton RESET
situ\u00e9 \u00e0 l'arri\u00e8re de la carte.
for
","text":"Le programme suivant utilise une boucle for
pour faire d\u00e9filer un pixel sur une ligne. Ex\u00e9cutez-le.
from microbit import *\nwhile True:\n for i in range(5):\n display.set_pixel(i,0,9)\n sleep(200)\n display.clear()\n
"},{"location":"T3_Architecture_materielle/3.1_Microbit/cours/#24-les-entrees-boutons-a-b-et-ab-programmation-evenementielle-video-explicative","title":"2.4 Les entr\u00e9es boutons A, B et A+B - programmation \u00e9v\u00e9nementielle (vid\u00e9o explicative)","text":"Il y a deux boutons sur la face avant du micro:bit (\u00e9tiquet\u00e9s A et B). On peut d\u00e9tecter quand ces boutons sont press\u00e9s, ce qui permet de d\u00e9clencher des instructions sur l'appareil.
Exemples avec le boutton A: - button_a.is_pressed()
: renvoie True si le bouton sp\u00e9cifi\u00e9 est actuellement enfonc\u00e9 et False sinon. - button_a.was_pressed()
: renvoie True ou False pour indiquer si le bouton a \u00e9t\u00e9 appuy\u00e9 depuis le d\u00e9marrage de l'appareil ou la derni\u00e8re fois que cette m\u00e9thode a \u00e9t\u00e9 appel\u00e9e.
Exemple : Essayer le programme suivant qui fait d\u00e9filer le texte \"NSI\" ind\u00e9finiment. On introduit l'instruction conditionnelle if
qui va tester si le bouton A a \u00e9t\u00e9 press\u00e9 (pendant le d\u00e9filement du texte ou pendant la pause), auquel cas le programme s'arr\u00eate en ex\u00e9cutant la commande break
.
from microbit import *\nwhile True:\n display.scroll(\"NSI\")\n sleep(200)\n if button_a.was_pressed():\n break\n
Exercice 1
\u00c9nonc\u00e9CorrectionCr\u00e9er le code permettant de basculer d'un visage triste \u00e0 un visage heureux suivant qu'on appuie sur A ou sur B.
from microbit import *\ndisplay.clear()\nwhile True:\n if button_a.was_pressed():\n display.show(Image.SAD)\n if button_b.was_pressed():\n display.show(Image.HAPPY)\n
Exercice 2
\u00c9nonc\u00e9CorrectionOn veut cr\u00e9er le code permettant de d\u00e9placer un point vers la gauche ou vers la droite en appuyant sur A ou sur B.
Compl\u00e9ter le code propos\u00e9 :
from microbit import *\ndisplay.clear()\ni = 12\nwhile True:\n x = ... # \u00e0 compl\u00e9ter\n y = ... # \u00e0 compl\u00e9ter\n display.set_pixel(x,y,9)\n if button_a.was_pressed():\n display.set_pixel(x,y,0)\n i = i - 1\n if i < 0 : \n i = 0\n if button_b.was_pressed():\n display.set_pixel(x,y,0)\n i = i + 1\n if i > 24 :\n i = 24\n
Exercice 3
\u00c9nonc\u00e9CorrectionCr\u00e9er le code permettant de faire d\u00e9filer toutes les images disponibles. Bouton B pour passer \u00e0 l'image suivante, bouton A pour revenir \u00e0 l'image pr\u00e9c\u00e9dente.
Compl\u00e9ter le code propos\u00e9 :
from microbit import *\n\nlst = [Image.HEART, Image.HEART_SMALL, Image.HAPPY, Image.SMILE,\n Image.SAD, Image.CONFUSED, Image.ANGRY, Image.ASLEEP, Image.SURPRISED, Image.SILLY,\n Image.FABULOUS, Image.MEH, Image.YES, Image.NO, Image.CLOCK12,\n Image.CLOCK11, Image.CLOCK10, Image.CLOCK9, Image.CLOCK8, Image.CLOCK7,\n Image.CLOCK6, Image.CLOCK5, Image.CLOCK4, Image.CLOCK3, Image.CLOCK2,\n Image.CLOCK1, Image.ARROW_N, Image.ARROW_NE, Image.ARROW_E, Image.ARROW_SE,\n Image.ARROW_S, Image.ARROW_SW, Image.ARROW_W, Image.ARROW_NW, Image.TRIANGLE,\n Image.TRIANGLE_LEFT, Image.CHESSBOARD, Image.DIAMOND, Image.DIAMOND_SMALL, Image.SQUARE,\n Image.SQUARE_SMALL, Image.RABBIT, Image.COW, Image.MUSIC_CROTCHET, Image.MUSIC_QUAVER,\n Image.MUSIC_QUAVERS, Image.PITCHFORK, Image.XMAS, Image.PACMAN, Image.TARGET, Image.TSHIRT,\n Image.ROLLERSKATE, Image.DUCK, Image.HOUSE, Image.TORTOISE, Image.BUTTERFLY, Image.STICKFIGURE,\n Image.GHOST, Image.SWORD, Image.GIRAFFE, Image.SKULL, Image.UMBRELLA, Image.SNAKE]\n
"},{"location":"T3_Architecture_materielle/3.1_Microbit/cours/#25-capteur-de-lumiere-video","title":"2.5 Capteur de lumi\u00e8re (vid\u00e9o)","text":"En inversant les LEDs d'un \u00e9cran pour devenir un point d'entr\u00e9e, l'\u00e9cran LED devient un capteur de lumi\u00e8re basique, permettant de d\u00e9tecter la luminosit\u00e9 ambiante.
La commande display.read_light_level()
retourne un entier compris entre 0 et 255 repr\u00e9sentant le niveau de lumi\u00e8re.
Exercice : Compl\u00e9ter le programme ci-dessous qui affiche une image de lune si on baisse la luminosit\u00e9 (en recouvrant la carte avec sa main par exemple) et un soleil sinon.
from microbit import *\n\nsoleil = Image(\"90909:\"\n \"09990:\"\n \"99999:\"\n \"09990:\"\n \"90909:\")\n\nlune = Image(\"00999:\"\n \"09990:\"\n \"09900:\"\n \"09990:\"\n \"00999:\")\n\nwhile True:\n if display.read_light_level()> ... : #trouver la bonne valeur (entre 0 et 255)\n display.show(soleil)\n else:\n display.show(...) #trouver la bonne variable\n sleep(10)\n
Prolongement: cr\u00e9er un programme qui affiche le niveau de luminosit\u00e9 et le tester avec la LED d'un t\u00e9l\u00e9phone portable ou une lampe-torche par exemple. Plus la luminosit\u00e9 sera \u00e9lev\u00e9e, plus il y aura de LEDs affich\u00e9es sur la matrice.
"},{"location":"T3_Architecture_materielle/3.1_Microbit/cours/#26-capteur-de-temperature-video","title":"2.6 Capteur de temp\u00e9rature (vid\u00e9o)","text":"Le micro:bit n\u2019a pas un capteur de temp\u00e9rature d\u00e9di\u00e9. Au lieu de cela, la temp\u00e9rature fournie est en fait la temp\u00e9rature de la puce de silicium du processeur principal. Comme le processeur chauffe peu en fonctionnement (c'est un processeur ARM \u00e0 grande efficacit\u00e9), sa temp\u00e9rature est une bonne approximation de la temp\u00e9rature ambiante. L'instruction temperature()
renvoie la temp\u00e9rature de la carte micro:bit en degr\u00e9s Celsius.
Exercice : Ecrire un programme qui affiche la temp\u00e9rature (aide: on pourra utiliser l'instruction display.scroll()
; revoir le point 2.1.1).
Un acc\u00e9l\u00e9rom\u00e8tre mesure l'acc\u00e9l\u00e9ration de la carte micro:bit, ce composant d\u00e9tecte quand la micro:bit est en mouvement. Il peut aussi d\u00e9tecter d'autres actions (gestes), par exemple quand elle est secou\u00e9e, inclin\u00e9e ou qu'elle tombe.
La carte micro:bit est munie d\u2019un acc\u00e9l\u00e9rom\u00e8tre. Il mesure le mouvement selon trois axes :
Dans l'exemple suivant \u00e0 essayer, l'instruction accelerometer.get_x()
permet de d\u00e9tecter un mouvement de gauche \u00e0 droite en renvoyant un nombre compris entre -1023 et 1023; 0 \u00e9tant la position \"d'\u00e9quilibre\"
#Exemple\nfrom microbit import *\n\nwhile True:\n abscisse = accelerometer.get_x()\n if abscisse > 500:\n display.show(Image.ARROW_E)\n elif abscisse < -500:\n display.show(Image.ARROW_W)\n else:\n display.show(\"-\")\n
Prolongement (secouer les d\u00e9s!):
Exercice 4
\u00c9nonc\u00e9Correction\u00c9crire un programme qui simule un d\u00e9 en affichant une face au hasard lorsque la micro:bit est secou\u00e9e. On pourra utiliser l'instruction accelerometer.is_gesture(shake)
qui teste si la carte est secou\u00e9e. Plus d'informations sur les gestes ici.
La boussole d\u00e9tecte le champ magn\u00e9tique de la Terre, nous permettant de savoir quelle direction la micro:bit indique. La boussole doit \u00eatre \u00e9talonn\u00e9e avant de pouvoir \u00eatre utilis\u00e9e. Pour cela, on utilise compass.calibrate()
qui ex\u00e9cute un petit jeu: au d\u00e9part, micro:bit fait d\u00e9filer \"Tilt to fill screen\". Ensuite, incliner micro:bit pour d\u00e9placer le point au centre de l\u2019\u00e9cran autour jusqu'\u00e0 ce que vous ayez rempli la totalit\u00e9 de l\u2019\u00e9cran.
La fonction compass.heading()
donne le cap de la boussole sous la forme d'un entier compris entre 0 et 360, repr\u00e9sentant l'angle en degr\u00e9s, dans le sens des aiguilles d'une montre, avec le nord \u00e9gal \u00e0 0.
Exercice : Compl\u00e9ter le programme suivant qui indique le Nord.
from microbit import *\n\ncompass.calibrate()\n\nwhile True:\n if compass.heading() < \"remplir ici\" or compass.heading() > \"remplir ici\":\n display.show(Image.ARROW_N)\n else:\n display.show(Image.DIAMOND_SMALL)\n
Prolongement: Am\u00e9liorer le programme pour que le micro:bit indique \"N\", \"S\", \"E\" et \"O\" en fonction de l'orientation de la boussole.
Autre prolongement: fabriquer une station m\u00e9t\u00e9o qui d\u00e9termine la direction du vent.
Autre prolongement: \u00e9tudier l'intensit\u00e9 du champ magn\u00e9tique autour du p\u00e9riph\u00e9rique (en utilisant la fonction compass.get_field_strength()
). Plus d'informations sur les fonctions \"boussole\" ici.
document bas\u00e9 sur le travail de Thomas Basso, acad\u00e9mie de Polyn\u00e9sie
"},{"location":"T3_Architecture_materielle/3.2_Architecture_Von_Neumann/cours/","title":"3.2 Architecture Von Neumann","text":"John Von Neumann (1903-1957) est un math\u00e9maticien et physicien (et bien d'autres choses) am\u00e9ricano-hongrois. Il a le premier th\u00e9oris\u00e9 l'architecture des processeurs, tels qu'ils fonctionnent encore aujourd'hui.
"},{"location":"T3_Architecture_materielle/3.2_Architecture_Von_Neumann/cours/#1-architecture-von-neumann","title":"1. Architecture von Neumann","text":"On distingue 4 zones essentielles :
Cette activit\u00e9 est disponible ici en vid\u00e9o.
"},{"location":"T3_Architecture_materielle/3.2_Architecture_Von_Neumann/cours/#21-le-programme-que-nous-etudierons","title":"2.1 Le programme que nous \u00e9tudierons","text":"a = 3\nb = 5\nc = a + b\n
Ce programme est ici \u00e9crit en langage Python. Le processeur ne comprend pas ce langage : les instructions doivent lui \u00eatre pass\u00e9es en langage-machine. C'est le r\u00f4le des interpr\u00e9teurs (pour le Python, par exemple) ou des compilateurs (pour le C, par exemple) que de faire le lien entre le langage pratiqu\u00e9 par les humains (Python, C...) et le langage-machine, qui n'est qu'une succession de chiffres binaires.
Par exemple, notre code ci-dessus s'\u00e9crit
01010000 00001111 00011000 00000000\n00000000 00000000 01010000 00111111\n00011100 00000000 00000000 00000000\n01100000 00000011 01000000 00111111\n00100000 00000000 00000000 00000000\n00000000 00000000 00000000 00000000\n00000011 00000000 00000000 00000000\n00000101 00000000 00000000 00000000\n
en langage-machine. Comment a lieu cette transformation ?
"},{"location":"T3_Architecture_materielle/3.2_Architecture_Von_Neumann/cours/#22-au-plus-proche-de-la-machine-mais-encore-humainement-comprehensible-le-langage-assembleur","title":"2.2 Au plus proche de la machine mais encore humainement compr\u00e9hensible : le langage assembleur","text":"Il existe un langage dit de \"bas-niveau\" (au sens qu'il est plus proche du langage machine qu'un langage de haut-niveau comme le Python) qui permet de passer des instructions directement au processeur : c'est le langage assembleur (ou ASM).
En assembleur, notre programme s'\u00e9crirait (par exemple) :
.pos 0\n mrmovl a, %eax\n mrmovl b, %ebx\n addl %eax, %ebx\n rmmovl %ebx, c\n halt\n\n.align 4\na: .long 3\nb: .long 5\nc: .long 0 \n
Le simulateur Y86 permet de simuler la mani\u00e8re dont le processeur va ex\u00e9cuter ce programme.
Vous pouvez retrouver le programme \u00e0 charger ici.
Sur la partie droite du simulateur, la zone M\u00e9moire contient, apr\u00e8s assemblage, la traduction de notre code en langage-machine :
500f1800\n0000503f\n1c000000\n6003403f\n20000000\n00000000\n03000000\n05000000\n
Une fois transform\u00e9 en binaire, on retrouve le code donn\u00e9 au d\u00e9but du paragraphe pr\u00e9c\u00e9dent.
Ressources sur les instructions Y86
Exercice
\u00c9nonc\u00e9CorrectionCoder en assembleur la s\u00e9quence d'instruction suivante :
w = 10\nx = 3\ny = 5\nz = w - (x + y)\n
Vous aurez pour cela besoin de l'instruction subl rA rB
qui effectue l'op\u00e9ration rB-rA
et la stocke dans rB
. (rA
et rB
sont les noms des registres).
.pos 0\nmrmovl x, %eax\nmrmovl y, %ebx\nmrmovl w, %ecx\naddl %eax, %ebx\nsubl %ebx, %ecx\nrmmovl %ecx, z\nhalt\n\n.align 4\nw: .long 10\nx: .long 3\ny: .long 5\nz: .long 0\n
"},{"location":"T3_Architecture_materielle/3.2_Architecture_Von_Neumann/cours/#24-resume-des-notions-essentielles","title":"2.4 R\u00e9sum\u00e9 des notions essentielles","text":"03
situ\u00e9 \u00e0 l'adresse 0x000d
signifie qu'il va falloir ajouter (on le sait gr\u00e2ce au 60
qui pr\u00e9c\u00e8de) le registre num\u00e9rot\u00e9 0
(donc %eax
) au registre num\u00e9rot\u00e9 3
(donc %ebx
). On retrouve un octet de m\u00eame valeur 03
\u00e0 l'adresse 0x0018
. Mais dans ce cas, cet octet n'est pas une instruction mais une simple donn\u00e9e : c'est la valeur 3 qu'on a donn\u00e9e \u00e0 la variable a
dans notre programme. Le simulateur Y86 nous a permis d'observer comment un processeur r\u00e9alise des op\u00e9rations \u00e9l\u00e9mentaires. Nous avons d\u00e9couvert le langage assembleur, qui est un langage beaucoup moins agr\u00e9able qu'un langage de haut-niveau, mais qui reste n\u00e9anmoins compr\u00e9hensible par un \u00eatre humain. Certains informaticiens codent (encore de nos jours) directement en langage assembleur, pour \"coller\" au mieux au processeur et optimiser les ressources.
"},{"location":"T3_Architecture_materielle/3.2_Architecture_Von_Neumann/cours/#3-activite-2-modification-dun-programme-par-desassemblage","title":"3. Activit\u00e9 2 : modification d'un programme par d\u00e9sassemblage","text":"On consid\u00e8re ci-dessous le programme crackme.c
, r\u00e9dig\u00e9 en langage en C. Vous pouvez t\u00e9l\u00e9charger ce programme ici.
#include \"stdio.h\"\n#include \"stdlib.h\"\n#include \"string.h\"\n\nint main()\n{\n\nchar saisie[50] = \"\";\nprintf(\"Acc\u00e8s restreint : saisissez votre mot de passe \\n\");\nwhile (strcmp(saisie,\"NSIMAURIAC\")!=0)\n{\nprintf(\"Mot de passe ? \\n\");\nscanf(\"%s\",&saisie);\n}\n\nprintf(\"Acc\u00e8s autoris\u00e9 \\n\");\n\nreturn 0;\n}
gcc crackme.c -o crackme
./crackme
et jouez avec le programme.\u00c0 l'aide du programme GHex , il est possible d'aller observer la valeur des octets directement dans le fichier binaire crackme
.
Ce fichier binaire est \u00e9crit en langage-machine. Il est donc incompr\u00e9hensible pour un autre humain... m\u00eame si GHex nous aide en affichant notamment (dans la partie droite) les cha\u00eenes de caract\u00e8res... dont notre mot de passe ;)
"},{"location":"T3_Architecture_materielle/3.2_Architecture_Von_Neumann/cours/#33-modification-du-fichier-binaire","title":"3.3 Modification du fichier binaire","text":"Dans notre code C l'instruction while (strcmp(saisie,\"NSIMAURIAC\")!=0)
est le c\u0153ur de la v\u00e9rification du mot de passe. En assembleur, elle va donner naissance \u00e0 une instruction JNE
(pour Jump if Not Equal, voir ici ). Cette instruction est cod\u00e9e en hexad\u00e9cimal par l'opcode 75 C5
. Nous allons rechercher ces octets et les remplacer par 90 90
, 90
\u00e9tant l'opcode pour NOP
(ne rien faire).
75 C5
.90 90
.crackme2
. Vous pouvez sinon le t\u00e9l\u00e9charger ici sudo chmod 777 crackme2
Le d\u00e9sassemblage d'un programme est une op\u00e9ration tr\u00e8s complexe et les op\u00e9rations et cha\u00eenes de caract\u00e8res qui apparaissent sont souvent incompr\u00e9hensibles (parfois volontairement, dans le cas d'obfuscation de code). N\u00e9anmoins, il est parfois possible d'agir au niveau le plus bas (le langage-machine) pour modifier un code, comme nous venons de le faire.
BibliographieCe cours a pour but de pr\u00e9senter la constitution classique d'un r\u00e9seau, et les \u00e9quipements associ\u00e9s. La partie relative aux protocoles utilis\u00e9s lors des \u00e9changes entre deux machines est d\u00e9taill\u00e9e dans le cours sur les protocoles de communication.
"},{"location":"T3_Architecture_materielle/3.3_Architecture_reseau/cours/#1-premier-reseau-local","title":"1. Premier r\u00e9seau local","text":"lien de t\u00e9l\u00e9chargement de Filius sous Linux
Au sein du logiciel Filius, cr\u00e9ons le r\u00e9seau local ci-dessous :
Testons le ping
de la machine 192.168.0.1
vers la machine 192.168.0.3
.
Chaque ordinateur sur le r\u00e9seau dispose d'une adresse MAC, qui une valeur unique attribu\u00e9e \u00e0 sa carte r\u00e9seau (Ethernet, Wifi, 4G, 5G, ...) lors de sa fabrication en usine.
Cette adresse est cod\u00e9e sur 48 bits, pr\u00e9sent\u00e9s sous la forme de 6 octets en hexad\u00e9cimal. Exemple : fc:aa:14:75:45:a5
Les trois premiers octets correspondent au code du fabricant. Un site comme https://www.macvendorlookup.com/ vous permet de retrouver le fabricant d'une adresse MAC quelconque.
"},{"location":"T3_Architecture_materielle/3.3_Architecture_reseau/cours/#12-switch-hub-quelle-difference","title":"1.2. Switch, hub, quelle diff\u00e9rence ?","text":"Rajoutons un deuxi\u00e8me sous-r\u00e9seau de la mani\u00e8re suivante (penser \u00e0 bien renommer les switchs).
Comment relier ces deux sous-r\u00e9seaux ?
Une r\u00e9ponse pas si b\u00eate : avec un cable entre les deux switchs !
Testons cette hypoth\u00e8se en essayant de pinger la machine 192.168.1.2
depuis la machine 192.168.0.1
.
Cela ne marche pas. L'ordinateur refuse d'envoyer le ping vers la machine 192.168.1.2
. (spoil : car elle n'est pas dans son sous-r\u00e9seau)
Temporairement, renommons la machine 192.168.1.2
en 192.168.0.33
. Testons \u00e0 nouveau le ping depuis la machine 192.168.0.1
.
Cela marche. Les paquets sont bien achemin\u00e9s.
Intuition : la notion de sous-r\u00e9seau n'est pas topologique (\u00abil suffit de relier les ordinateurs entre eux\u00bb) mais ob\u00e9it \u00e0 des r\u00e8gles num\u00e9riques.
"},{"location":"T3_Architecture_materielle/3.3_Architecture_reseau/cours/#21-notion-de-masque-de-sous-reseau","title":"2.1. Notion de masque de sous-r\u00e9seau","text":"Dans Filius, lors de l'attribution de l'adresse IP \u00e0 une machine, une ligne nous permet de sp\u00e9cifier le masque de sous-r\u00e9seau (appel\u00e9 simplement \u00ab Masque \u00bb dans Filius). C'est ce masque qui va permettre de d\u00e9terminer si une machine appartient \u00e0 un sous-r\u00e9seau ou non, en fonction de son adresse IP.
"},{"location":"T3_Architecture_materielle/3.3_Architecture_reseau/cours/#211-explication-basique","title":"2.1.1 Explication basique","text":"255.255.255.0
, toutes les machines partageant les m\u00eames trois premiers nombres de leur adresse IP appartiendront au m\u00eame sous-r\u00e9seau. Comme ceci est le r\u00e9glage par d\u00e9faut de Filius, cela explique pourquoi 192.168.0.33
et 192.168.0.1
sont sur le m\u00eame sous-r\u00e9seau, et pourquoi 192.168.1.2
et 192.168.0.1
ne sont pas sur le m\u00eame sous-r\u00e9seau.Dans cette configuration, 256 machines peuvent donc appartenir au m\u00eame sous-r\u00e9seau (ce n'est pas tout \u00e0 fait le cas car des adresses finissant par 0 ou par 255 sont r\u00e9serv\u00e9es).
255.255.0.0
, toutes les machines partageant les m\u00eames deux premiers nombres de leur adresse IP appartiendront au m\u00eame sous-r\u00e9seau. Dans cette configuration, 65536 machines peuvent \u00eatre dans le m\u00eame sous-r\u00e9seau. (car 256^2=65536)Exercice
192.168.0.33
en 192.168.1.2
et modifions son masque en 255.255.0.0
.192.168.0.1
en 255.255.0.0
.192.168.0.1
vers 192.168.1.2
.Cela marche. Les deux machines appartiennent maintenant au m\u00eame sous-r\u00e9seau.
"},{"location":"T3_Architecture_materielle/3.3_Architecture_reseau/cours/#212-explication-avancee","title":"2.1.2 Explication avanc\u00e9e","text":"Lorsqu'une machine A veut envoyer un message \u00e0 une machine B, elle doit d\u00e9terminer si cette machine :
Quelle op\u00e9ration permet de distinguer cette appartenance \u00e0 un m\u00eame sous-r\u00e9seau ?
Appelons IP_A
et IP_B
les adresses IP respectives des machines A et B. Appelons M
le masque de sous-r\u00e9seau. Nommons &
l'op\u00e9rateur de conjonction entre nombres binaires (voir ici):
Propri\u00e9t\u00e9 : A et B appartiennent au m\u00eame sous-r\u00e9seau \u21d4 IP_A & M = IP_B & M
Exemple : consid\u00e9rons trois machines A, B, C d'IP respectives 192.168.129.10
, 192.168.135.200
et 192.168.145.1
, configur\u00e9es avec un masque de sous-r\u00e9seau \u00e9gal \u00e0 255.255.248.0
.
rappel des r\u00e8gles de calcul :
x
, x & 255 = x
et x & 0 = 0
.129 & 248
s'\u00e9crit en binaire 10000001 & 11111000
qui vaut 10000000
, soit 128
en d\u00e9cimal.Conclusion : les machines A et B sont sous le m\u00eame sous-r\u00e9seau, mais pas la machine C.
"},{"location":"T3_Architecture_materielle/3.3_Architecture_reseau/cours/#213-coherence-entre-les-deux-explications","title":"2.1.3 Coh\u00e9rence entre les deux explications","text":"Lorsqu'un masque de sous-r\u00e9seau est \u00e9gal \u00e0 255.255.255.0
, l'op\u00e9ration de conjonction &
avec chaque IP ne laissera intacts que les 3 premiers octets, le dernier sera \u00e9gal \u00e0 0. Donc si deux adresses s'\u00e9crivent A.B.C.X
et A.B.C.Y
, elles appartiendront forc\u00e9ment au m\u00eame sous-r\u00e9seau (typiquement, c'est le cas de 192.168.0.33
et 192.168.0.1
).
D'apr\u00e8s ce qui pr\u00e9c\u00e8de, 2 informations sont n\u00e9cessaires pour d\u00e9terminer le sous-r\u00e9seau auquel appartient une machine : son IP et le masque de sous-r\u00e9seau. Une convention de notation permet d'\u00e9crire simplement ces deux renseignements : la notation CIDR.
Exemple : Une machine d'IP 192.168.0.33
avec un masque de sous-r\u00e9seau 255.255.255.0
sera d\u00e9sign\u00e9e par 192.168.0.33 / 24
en notation CIDR.
Le suffixe / 24
signifie que le masque de sous-r\u00e9seau commence par 24 bits cons\u00e9cutifs de valeur 1 : le reste des bits (donc 8 bits) est \u00e0 mis \u00e0 0. Autrement dit, ce masque vaut 11111111.11111111.11111111.00000000
, soit 255.255.255.0
. De la m\u00eame mani\u00e8re, le suffixe / 16
donnera un masque de 11111111.11111111.00000000.00000000
, soit 255.255.0.0
. Ou encore, un suffixe / 21
donnera un masque de 11111111.11111111.11111000.00000000
, soit 255.255.248.0
.
D\u00e9finition
0.0.0.0
\u00e0 255.255.255.255
.Exemple
"},{"location":"T3_Architecture_materielle/3.3_Architecture_reseau/cours/#3-un-vrai-reseau-contenant-deux-sous-reseaux-distincts-la-necessite-dun-routeur","title":"3. Un vrai r\u00e9seau contenant deux sous-r\u00e9seaux distincts : la n\u00e9cessit\u00e9 d'un routeur","text":"Notre solution initiale (relier les deux switchs par un cable pour unifier les deux sous-r\u00e9seaux) n'est pas viable \u00e0 l'\u00e9chelle d'un r\u00e9seau plan\u00e9taire.
Pour que les machines de deux r\u00e9seaux diff\u00e9rents puissent \u00eatre connect\u00e9es, on va utiliser un dispositif \u00e9quip\u00e9 de deux cartes r\u00e9seaux, situ\u00e9 \u00e0 cheval entre les deux sous-r\u00e9seaux. Ce \u00e9quipement de r\u00e9seau est appel\u00e9 routeur ou passerelle.
"},{"location":"T3_Architecture_materielle/3.3_Architecture_reseau/cours/#31-principe-de-fonctionnement","title":"3.1 Principe de fonctionnement","text":"Imaginons que la machine 192.168.0.1 / 24
veuille communiquer avec la machine 172.16.52.3 / 24
. L'observation du masque de sous-r\u00e9seau de la machine 192.168.0.1 / 24
nous apprend qu'elle ne peut communiquer qu'avec les adresses de la forme 192.168.0.X / 24
, o\u00f9 X
est un nombre entre 0 et 255.
Les 3 \u00e9tapes du routage :
Dans notre exemple, l'adresse 172.16.52.3
n'est pas dans le sous-r\u00e9seau de 192.168.0.1
. Le message va donc transiter par le routeur.
Rajoutons un routeur entre le SwitchA et le SwitchB.
Configuration du routeur : L'interface reli\u00e9e au Switch A doit avoir une adresse du sous-r\u00e9seau A. On donne souvent une adresse finissant par 254
, qui est en quelque sorte la derni\u00e8re adresse du r\u00e9seau (en effet l'adresse en 255
est appel\u00e9e adresse de broadcast, utilis\u00e9e pour pinger en une seule fois l'int\u00e9gralit\u00e9 d'un sous-r\u00e9seau). On donne donc l'adresse 192.168.0.254
pour l'interface reli\u00e9e au Switch A, et 192.168.1.254
pour l'interface reli\u00e9e au Switch B. Dans l'onglet g\u00e9n\u00e9ral, s\u00e9lectionner \u00ab Routage automatique \u00bb. Ainsi configur\u00e9 notre routeur peut jouer le r\u00f4le de passerelle entre les deux sous-r\u00e9seaux.
192.168.0.1
et 192.168.1.2
Cela ne marche pas. La carte r\u00e9seau refuse d'envoyer les paquets car elle ne sait pas o\u00f9 les envoyer.
Pourquoi cet \u00e9chec ? Parce que nous devons dire \u00e0 chaque machine qu'une passerelle est maintenant disponible pour pouvoir sortir de son propre sous-r\u00e9seau. Il faut donc aller sur la machine 192.168.0.1
et lui donner l'adresse de sa passerelle, qui est 192.168.0.254
.
Attention, il faut faire de m\u00eame pour 192.168.1.2
(avec la bonne passerelle...) Testons \u00e0 nouveau le ping... Cette fois cela marche.
Plus int\u00e9ressant : effectuons un traceroute
entre 192.168.0.1
et 192.168.1.2
.
On y aper\u00e7oit que la machine 192.168.1.2
est atteignable en deux sauts depuis 192.168.0.1
, en passant par la passerelle 192.168.0.254
Cas d'un r\u00e9seau domestique
Chez vous, la box de votre op\u00e9rateur joue simultan\u00e9ment le r\u00f4le de switch et de routeur :
L'image ci-dessous pr\u00e9sente le r\u00e9sultat de la commande ipconfig
sous Windows. On y retrouve l'adresse IP locale 192.168.9.103
, le masque de sous-r\u00e9seau 255.255.255.0
et l'adresse de la passerelle 192.168.9.1
.
Connectons un ordinateur au SwitchB, sur l'adresse 192.168.1.30
et installons dessus un Serveur web et d\u00e9marrons-le.
Sur la machine 192.168.0.1
, rajoutons un Navigateur Web. En tapant dans la barre d'adresse l'adresse IP du Serveur web, la page d'accueil de Filius s'affiche.
Lors d'une utilisation classique d'un navigateur web, c'est une url m\u00e9morisable qui s'affiche, et non une adresse IP : on retient en effet plus facilement https://www.google.com/
que http://216.58.213.131
, qui renvoient pourtant \u00e0 la m\u00eame adresse. La machine qui assure ce r\u00f4le d'annuaire entre les serveurs web et leur adresse IP s'appelle un serveur DNS. Pour pouvoir indexer la totalit\u00e9 des sites internet, son r\u00f4le est structur\u00e9 de mani\u00e8re hi\u00e9rarchique. Vous trouverez des d\u00e9tails ici
Sur ce serveur DNS, associons l'adresse http://www.vivelansi.fr
\u00e0 l'adresse IP 192.168.1.30
.
De retour sur notre machine 192.168.0.1
, sp\u00e9cifions maintenant l'adresse du serveur DNS :
Depuis le navigateur web de la machine 192.168.0.1
, le site http://www.vivelansi.fr
est maintenant accessible.
Bibliographie
Les bits transmis d'un ordinateur \u00e0 un autre contiennent, en plus des donn\u00e9es utiles (le mot \u00abbonjour\u00bb dans un email), une multitude de donn\u00e9es (tout aussi utiles) qui vont aider \u00e0 l'acheminement de ces bits au bon endroit, puis au bon ordinateur, puis au bon logiciel. Les diff\u00e9rents protocoles qui r\u00e9gissent cette transmission sont regroup\u00e9s dans ce qui est appel\u00e9 un mod\u00e8le. Deux mod\u00e8les synth\u00e9tisent ces protocoles :
Ces deux mod\u00e8les co\u00efncident suivant le sch\u00e9ma ci-dessus. Ce sont des mod\u00e8les th\u00e9oriques et d'une certaine rigidit\u00e9. Leur utilisation dans la pratique est parfois plus floue, avec des protocoles \u00e0 cheval sur plusieurs couches. Dans la suite de ce cours, nous \u00e9voquerons les couches par leur num\u00e9ro dans le mod\u00e8le OSI.
Lors de son \u00e9mission, un message va subir successivement toutes les transformations effectu\u00e9es par chaque couche, depuis sa cr\u00e9ation (couche 7) jusqu'\u00e0 sa transmission physique (couche 1).
Lorsque ce m\u00eame message sera r\u00e9ceptionn\u00e9, les transformations seront effectu\u00e9es dans l'ordre inverse, jusqu'\u00e0 la pr\u00e9sentation du message au destinataire.
couches 7-6-5 \u2014 couches application-pr\u00e9sentation-session : Ces couches (r\u00e9unies dans le mod\u00e8le Internet en une couche unique \u00abapplication\u00bb ) regroupent les protocoles n\u00e9cessaires \u00e0 la bonne mise en forme d'un message (au sens large) avant sa transmission. Ces protocoles peuvent \u00eatre de nature tr\u00e8s diff\u00e9rente : protocole HTTP pour la transmisson de pages web, protocole FTP pour le transfert de fichiers, protocoles POP ou IMAP pour le courrier \u00e9lectronique...
couche 4 \u2014 couche transport : Le protocole majeur de cette couche est le protocole TCP :
couche 3 \u2014 couche r\u00e9seau : C'est la couche o\u00f9 chaque segment num\u00e9rot\u00e9 est encapsul\u00e9 dans un paquet qui, suivant le protocole IP, va contenir son adresse source et son adresse de destination. C'est \u00e0 ce niveau que se d\u00e9cide si le message doit rester dans le r\u00e9seau local ou \u00eatre envoy\u00e9 sur un autre r\u00e9seau via la passerelle du routeur. Les \u00e9l\u00e9ments \u00e9chang\u00e9s avec la couche inf\u00e9rieure sont des paquets.
couche 2 \u2014 couche liaison : C'est l'encapsulation finale du message. Suivant le protocole Ethernet, les informations sont transmises d'une carte r\u00e9seau \u00e0 une autre, gr\u00e2ce \u00e0 leur adresse MAC (Media Access Controler). Les \u00e9l\u00e9ments \u00e9chang\u00e9s avec la couche inf\u00e9rieure sont des trames.
couche 1 \u2014 couche physique : C'est la couche o\u00f9 le message est transmis physiquement d'un point \u00e0 un autre. Par signal lumineux (fibre optique), par ondes (wifi), par courant \u00e9lectrique (Ethernet)... Les \u00e9l\u00e9ments transmis sont les bits.
Lors de son parcours, une trame peut \u00eatre partiellement d\u00e9capsul\u00e9e et remonter \u00e0 la couche 3, avant de redescendre et de continuer son chemin. C'est le cas notamment lors du passage dans un routeur. Mais jamais, lors de son acheminement, le contenu r\u00e9el du message n'est ouvert : les paquets transmis sont achemin\u00e9s de mani\u00e8re identique, qu'ils contiennent les \u00e9l\u00e9ments constitutifs d'une vid\u00e9o YouTube ou d'un email \u00e0 votre cousin.
Ce principe fondateur, actuellement menac\u00e9 par certains acteurs politiques et industriels, est connu sous l'expression \u00abla neutralit\u00e9 du net\u00bb.
"},{"location":"T3_Architecture_materielle/3.4_Protocoles_de_communication/cours/#2-observation-des-trames-avec-filius","title":"2. Observation des trames avec Filius","text":""},{"location":"T3_Architecture_materielle/3.4_Protocoles_de_communication/cours/#21-ping-a-travers-un-switch","title":"2.1. Ping \u00e0 travers un switch","text":"Vous pouvez t\u00e9l\u00e9charger le fichier ping_switch.fls.
192.168.0.10
d'adresse MAC BC:81:81:42:9C:31
\u00e0 une machine 192.168.0.11
d'adresse MAC 2A:AB:AC:27:D6:A7
\u00e0 travers un switch.
192.168.0.10
vers 192.168.0.11
et observons les donn\u00e9es \u00e9chang\u00e9es :
Cette premi\u00e8re ligne est une requ\u00eate ARP. ARP est un protocole qui s'interface entre la couche 3 / r\u00e9seau (appel\u00e9e dans la capture d'\u00e9cran Internet) et la couche 2 / liaison (appel\u00e9e dans la capture d'\u00e9cran R\u00e9seau). Comme indiqu\u00e9 dans le commentaire, elle consiste \u00e0 un appel \u00e0 tout le r\u00e9seau : \"Est-ce que quelqu'un ici poss\u00e8de l'IP 192.168.0.11
?
Message 1 : \u00ab Qui poss\u00e8de l'IP 192.168.0.11
? \u00bb
Il faut comprendre \u00e0 cette \u00e9tape que l'adresse IP est totalement inutile pour r\u00e9p\u00e9rer un ordinateur dans un sous-r\u00e9seau. Ce sont les adresses MAC qui permettent de se rep\u00e9rer dans un sous-r\u00e9seau. Les adresses IP, elles, permettront \u00e9ventuellement d'acheminer le message jusqu'au bon sous-r\u00e9seau (elles n'int\u00e9ressent donc que les routeurs).
Revenons \u00e0 notre ping vers 192.168.0.11
.
La commande arp -a
effectu\u00e9e dans un terminal de la machine 192.168.0.10
nous permet de voir qu'elle ne conna\u00eet encore personne dans son sous-r\u00e9seau. La table de correspondance IP \u2b80 MAC ne contient que l'adresse de broadcast 255.255.255.255
, qui permet d'envoyer un message \u00e0 tout le r\u00e9seau.
Constatant qu'elle ne sait pas quelle est l'adresse MAC de 192.168.0.11
, la machine 192.168.0.10
commence donc par envoyer un message \u00e0 tout le sous-r\u00e9seau, par l'adresse MAC de broadcast FF:FF:FF:FF:FF:FF
. Le switch va lui aussi lui aussi relayer ce message \u00e0 tous les \u00e9quipements qui lui sont connect\u00e9s (dans notre cas, un seul ordinateur)
Message 2 : \u00ab Moi ! \u00bb
La machine 192.168.0.11
s'est reconnu dans le message de broadcast de la machine 192.168.0.10
. Elle lui r\u00e9pond pour lui donner son adresse MAC.
\u00c0 partir de ce moment, la machine 192.168.0.10
sait comment communiquer avec 192.168.0.11
. Elle l'\u00e9crit dans sa table arp
, afin de ne plus avoir \u00e0 \u00e9mettre le message n\u00b01 :
Le switch, qui a vu passer sur ses ports 0 et 1 des messages venant des cartes MAC BC:81:81:42:9C:31
et 2A:AB:AC:27:D6:A7
, peut mettre \u00e0 jour sa table SAT :
Par la suite, il saura sur quel port rediriger les messages destin\u00e9s \u00e0 ces deux adresses MAC. Un switch est un \u00e9quipement de r\u00e9seau de la couche 2 du mod\u00e8le OSI, il ne sait pas lire les adresses IP : il ne travaille qu'avec les adresses MAC.
Message 3 : le ping est envoy\u00e9
Sch\u00e9matisons cette trame Ethernet (couche 2 du mod\u00e8le OSI) :
Message 4 : le pong est retourn\u00e9
"},{"location":"T3_Architecture_materielle/3.4_Protocoles_de_communication/cours/#22-ping-a-travers-un-routeur","title":"2.2. Ping \u00e0 travers un routeur","text":"
Vous pouvez t\u00e9l\u00e9charger le fichier ping_routeur.fls.
L'objectif est d'observer les diff\u00e9rentes trames lors d'un ping entre :
192.168.0.1 / 24
(adresse MAC F9:E1:D6:0B:29:03
) et192.168.1.1 / 24
(adresse MAC D3:79:96:B8:5C:A4
)Le routeur est configur\u00e9 ainsi :
192.168.0.254
77:C2:22:C9:5C:E7
192.168.1.254
66:E5:4E:7D:0B:B0
\u00c9tape 0 : le routeur signale sa pr\u00e9sence
Lors de l'observation des messages re\u00e7us ou \u00e9mis par la machine 192.168.0.1
, on peut \u00eatre intrigu\u00e9 par ce tout premier message re\u00e7u, \u00e9mis par le routeur :
On peut y distinguer les 4 couches du mod\u00e8le Internet. Le routeur, par ce message distribu\u00e9 \u00e0 tous les \u00e9l\u00e9ments du sous-r\u00e9seau A (il envoie un message \u00e9quivalent sur son sous-r\u00e9seau B), d\u00e9clare sa pr\u00e9sence, et le fait qu'il poss\u00e8de deux interfaces, une pour chaque r\u00e9seau. Il se positionne ainsi comme une passerelle : \u00abc'est par moi qu'il faudra passer si vous voulez sortir de votre sous-r\u00e9seau\u00bb. Dans cette trame envoy\u00e9e figure son adresse MAC, de sorte que tous les membres de son sous-r\u00e9seau pourront donc communiquer avec lui.
\u00c9tape 1 : de 192.168.0.1
vers le routeur
La machine 192.168.0.1 / 24
calcule que la machine 192.168.1.1 / 24
avec laquelle elle veut communiquer n'est pas dans son sous-r\u00e9seau. Elle va donc envoyer son message \u00e0 sa passerelle, qui est l'adresse du routeur dans son sous-r\u00e9seau.
Cette premi\u00e8re trame est :
\u00c9tape 2 : le routeur d\u00e9capsule la trame
Le routeur est un \u00e9quipement de r\u00e9seau de couche 3 (couche r\u00e9seau). Il doit observer le contenu du paquet IP (sans remonter jusqu'au contenu du message) pour savoir, suivant le proc\u00e9d\u00e9 de routage (voir cours de Terminale), o\u00f9 acheminer ce paquet.
Dans notre cas, l'adresse IP 192.168.1.1
de destination lui est accessible : elle fait partie de son sous-r\u00e9seau B.
Le routeur va modifier la valeur du TTL (Time To Live), en la d\u00e9cr\u00e9mentant de 1. Si, apr\u00e8s de multiples routages, cette valeur devenait \u00e9gale \u00e0 0, ce paquet serait d\u00e9truit. Ceci a pour but d'\u00e9viter l'encombrement des r\u00e9seaux avec des paquets ne trouvant pas leur destination.
NAT : translation d'adresseDans notre cas, le routeur va laisser intacte l'adresse IP Source. Ce n'est pas toujours le cas. Dans le cas classique de la box qui relie votre domicile \u00e0 internet, le routeur contenu dans celle-ci va remplacer l'adresse locale de votre ordinateur ou smartphone (ex 192.168.0.26
) par son IP publique (celle apparaissant sur whatsmyip.com, par exemple). Elle effectue ce qu'on appelle une translation d'adresse (NAT). Pourquoi ? Parce que sinon la r\u00e9ponse du serveur distant que vous interrogez serait envoy\u00e9e sur une adresse locale (votre adresse 192.168.0.26
), qui est introuvable depuis un r\u00e9seau ext\u00e9rieur. Il faut donc remplacer toutes les adresses locales par l'IP publique de votre box. Pour \u00e9viter que la r\u00e9ponse du serveur web que vous avez interrog\u00e9 ne soit affich\u00e9e sur l'ordinateur de vos parents, le routeur affecte des ports diff\u00e9rents \u00e0 chaque machine de son sous-r\u00e9seau. Ce port est inclus dans le message transmis au serveur, et il l'est aussi dans sa r\u00e9ponse : le routeur peut donc rediriger le trafic vers la bonne machine du sous-r\u00e9seau.
Le routeur va r\u00e9-encapsuler le paquet IP modifi\u00e9, et cr\u00e9er une nouvelle trame Ethernet en modifiant :
192.168.1.1
(qu'il aura peut-\u00eatre r\u00e9cup\u00e9r\u00e9e au pr\u00e9alable par le protocole ARP)Cette deuxi\u00e8me trame est donc :
On peut observer dans Filius cette trame, en se positionnant sur l'interface 192.168.1.254
du routeur, ou sur 192.168.1.1
:
En suivant le m\u00eame principe, la machine 192.168.1.1
pourra envoyer son pong.
Exercice de bac
\u00c9nonc\u00e9CorrectionParties 2 et 3 de l'exercice 2 du sujet Nouvelle-Cal\u00e9donie J1 2022.
Partie 2
Correction Q1.Le r\u00e9seau services a pour adresse IP 195.168.254.0
.
Le r\u00e9seau services a pour adresse 195.168.254.0
. Comme le masque de sous-r\u00e9seau utilis\u00e9 est 255.255.255.0
, 254 adresses sont initialement disponibles (195.168.254.1
\u00e0 195.168.254.254
, puisque l'adresse 195.168.254.255
est r\u00e9serv\u00e9e pour le broadcast sur le r\u00e9seau). Comme deux adresses sont d\u00e9j\u00e0 prises par le routeur 1 et le routeur 2, il en reste 252.
Le serveur web acc\u00e8de \u00e0 internet via le routeur 2, dont l'adresse sur le r\u00e9seau services est 192.168.254.2
. C'est donc cette adresse qui joue est l'adresse de passerelle pour le serveur web.
Partie 3
Correction Q1.La ligne 2 montre que l'adresse MAC du serveur DNS est 8A:FD:54:49:D0:CC
.
La couche Transport montre que le protocole utilis\u00e9 est le protocole UDP.
Correction Q3.Le commentaire de la couche Application indique que l'adresse IP du serveur web est 192.168.254.201
.
Ce protocole est un exemple simple de fiabilisation du transfert de donn\u00e9es.
"},{"location":"T3_Architecture_materielle/3.4_Protocoles_de_communication/cours/#1-contexte","title":"1. Contexte","text":"Dans cette situation, les sous-messages arrivent tous \u00e0 destination dans le bon ordre. La transmission est correcte.
"},{"location":"T3_Architecture_materielle/3.4_Protocoles_de_communication/cours/#3-situation-reelle","title":"3. Situation r\u00e9elle","text":"Mais parfois, les choses ne se passent pas toujours aussi bien. Car si on ma\u00eetrise parfaitement le timing de l'envoi des sous-messages d'Alice, on ne sait pas combien de temps vont mettre ces sous-messages pour arriver, ni m\u00eame (attention je vais passer dans un tunnel) s'ils ne vont pas \u00eatre d\u00e9truits en route.
Le sous-message M0 est arriv\u00e9 apr\u00e8s le M1, le message M2 n'est jamais arriv\u00e9...
Que faire ?
\u00c9cartons l'id\u00e9e de num\u00e9roter les sous-messages, afin que Bob puisse remettre dans l'ordre les messages arriv\u00e9s, ou m\u00eame redemander sp\u00e9cifiquement des sous-messages perdus. C'est ce que r\u00e9alise le protocole TCP (couche 4 \u2014 transport), c'est tr\u00e8s efficace, mais cher en ressources. Essayons de trouver une solution plus basique.
"},{"location":"T3_Architecture_materielle/3.4_Protocoles_de_communication/cours/#3-solution-naive","title":"3. Solution na\u00efve...","text":"Pourquoi ne pas demander \u00e0 Bob d'envoyer un signal pour dire \u00e0 Alice qu'il vient bien de recevoir son sous-message ? Nous appelerons ce signal ACK (comme acknowledgement, traduisible par \u00abaccus\u00e9 de r\u00e9ception\u00bb). Ce signal ACK permettra \u00e0 Alice de renvoyer un message qu'elle consid\u00e9rera comme perdu :
N'ayant pas re\u00e7u le ACK cons\u00e9cutif \u00e0 son message M1, Alice suppose (avec raison) que ce message n'est pas parvenu jusqu'\u00e0 Bob, et donc renvoie le message M1.
"},{"location":"T3_Architecture_materielle/3.4_Protocoles_de_communication/cours/#4-mais-peu-efficace","title":"4. Mais peu efficace...","text":"Le deuxi\u00e8me ACK de Bob a mis trop de temps pour arriver (ou s'est perdu en route) et donc Alice a suppos\u00e9 que son sous-message M1 n'\u00e9tait pas arriv\u00e9. Elle l'a donc renvoy\u00e9, et Bob se retrouve avec deux fois le sous-message M1. La transmission est incorrecte. En faisant transiter un message entre Bob et Alice, nous multiplions par 2 la probabilit\u00e9 que des probl\u00e8mes techniques de transmission interviennent. Et pour l'instant rien ne nous permet de les d\u00e9tecter.
"},{"location":"T3_Architecture_materielle/3.4_Protocoles_de_communication/cours/#5-bob-prend-le-controle","title":"5. Bob prend le contr\u00f4le","text":"Bob va maintenant int\u00e9grer une m\u00e9thode de validation du sous-message re\u00e7u. Il pourra d\u00e9cider de le garder ou de l'\u00e9carter. Le but est d'\u00e9viter les doublons.
Pour r\u00e9aliser ceci, Alice va rajouter \u00e0 chacun de ses sous-messages un bit de contr\u00f4le, que nous appelerons FLAG (drapeau). Au d\u00e9part, ce FLAG vaut 0. Quand Bob re\u00e7oit un FLAG, il renvoie un ACK \u00e9gal au FLAG re\u00e7u.
Alice va attendre ce ACK contenant le m\u00eame bit que son dernier FLAG envoy\u00e9 :
Bob, de son c\u00f4t\u00e9, va contr\u00f4ler la validit\u00e9 de ce qu'il re\u00e7oit : il ne gardera que les sous-messages dont le FLAG est \u00e9gal \u00e0 l'inverse de son dernier ACK. C'est cette m\u00e9thode qui lui permettra d'\u00e9carter les doublons.
Observons ce protocole dans plusieurs cas :
"},{"location":"T3_Architecture_materielle/3.4_Protocoles_de_communication/cours/#51-cas-ou-le-sous-message-est-perdu","title":"5.1 Cas o\u00f9 le sous-message est perdu","text":""},{"location":"T3_Architecture_materielle/3.4_Protocoles_de_communication/cours/#52-cas-ou-le-ack-est-perdu","title":"5.2 Cas o\u00f9 le ACK est perdu","text":"Le protocole a bien d\u00e9tect\u00e9 le doublon du sous-message M1.
"},{"location":"T3_Architecture_materielle/3.4_Protocoles_de_communication/cours/#53-cas-ou-un-sous-message-est-en-retard","title":"5.3 Cas o\u00f9 un sous-message est en retard","text":"Le protocole a bien d\u00e9tect\u00e9 le doublon du sous-message M1... mais que se passerait-il si notre premier sous-message M1 \u00e9tait encore plus en retard ?
"},{"location":"T3_Architecture_materielle/3.4_Protocoles_de_communication/cours/#6-conclusion","title":"6. Conclusion","text":"Le protocole du bit altern\u00e9 a longtemps \u00e9t\u00e9 utilis\u00e9 au sein de la couche 2 du mod\u00e8le OSI (distribution des trames Ethernet). Simple et l\u00e9ger, il peut toutefois \u00eatre facilement mis en d\u00e9faut, ce qui explique qu'il ait \u00e9t\u00e9 remplac\u00e9 par des protocoles plus performants.
Bibliographie - Num\u00e9rique et Sciences Informatiques, 1re, T. BALABONSKI, S. CONCHON, J.-C. FILLIATRE, K. NGUYEN, \u00e9ditions ELLIPSES. - Pr\u00e9pabac NSI 1\u00e8re, C.ADOBET, G.CONNAN, G. ROZSAVOLGYI, L.SIGNAC, \u00e9ditions Hatier.
"},{"location":"T3_Architecture_materielle/3.5_Decouverte_des_commandes_Linux/cours/","title":"3.5 D\u00e9couverte des commandes UNIX","text":"\u00e0 partir du jeu Terminus
Rendez-vous \u00e0 l'adresse http://luffah.xyz/bidules/Terminus/
Laissez-vous guider par le jeu, mais attention ! - vous devez noter sur un papier chaque nouvelle commande que vous apprenez. Vous pouvez par exemple construire un tableau de ce type :
Activit\u00e9 d'introduction
"},{"location":"T4_Algorithmique/4.1_Extremums_et_moyennes/cours/#1-algorithme-de-recherche-de-maximum","title":"1. Algorithme de recherche de maximum","text":"Recherche de maximum
def recherche_max(tab):\n'''renvoie le maximum de la liste tab'''\n maxi = tab[0] # (1)\n for elt in tab:\n if elt > maxi:\n maxi = elt\n return maxi\n
Utilisation :
>>> recherche_max([4, 3, 8, 1])\n 8\n
"},{"location":"T4_Algorithmique/4.1_Extremums_et_moyennes/cours/#2-algorithme-de-calcul-de-moyenne","title":"2. Algorithme de calcul de moyenne","text":"Calcul de moyenne
def moyenne(tab):\n''' renvoie la moyenne de tab'''\n somme = 0\n for elt in tab:\n somme += elt\n return somme / len(tab)\n
Utilisation :
>>> moyenne([4, 3, 8, 1])\n 4.0\n
"},{"location":"T4_Algorithmique/4.1_Extremums_et_moyennes/cours/#3-algorithme-de-recherche-doccurrence","title":"3. Algorithme de recherche d'occurrence","text":"Recherche d'occurrence
def recherche_occurrence(elt, tab):\n''' renvoie la liste (\u00e9ventuellement vide)\n des indices de elt dans tab'''\n liste_indices = []\n for i in range(len(tab)):\n if tab[i] == elt:\n liste_indices.append(i)\n return liste_indices\n
Utilisation :
>>> recherche_occurrence(3, [1, 6, 3, 8, 3, 2])\n[2, 4]\n>>> recherche_occurrence(7, [1, 6, 3, 8, 3, 2])\n[]\n
"},{"location":"T4_Algorithmique/4.1_Extremums_et_moyennes/intro_cours/","title":"Vers les extremums et moyennes","text":""},{"location":"T4_Algorithmique/4.1_Extremums_et_moyennes/intro_cours/#1-algorithme-de-recherche-de-maximum","title":"1. Algorithme de recherche de maximum","text":"On cherche \u00e0 coder une fonction recherche_max
qui prend en param\u00e8tre une liste tab
et qui renvoie le plus grand \u00e9l\u00e9ment de cette liste. L'usage de la fonction max
est interdit.
Utilisation :
>>> recherche_max([4, 3, 8, 1])\n 8\n
Code \u00e0 trous Recherche de maximum
def recherche_max(tab):\n'''renvoie le maximum de la liste tab'''\n
Code \u00e0 trous Recherche de maximum
def recherche_max(tab):\n'''renvoie le maximum de la liste tab'''\n ... = ... \n for ... in ...:\n if ... > ...:\n ... = ...\n return ...\n
Code \u00e0 trous Recherche de maximum
def recherche_max(tab):\n'''renvoie le maximum de la liste tab'''\n maxi = ... \n for elt in ...:\n if ... > ...:\n ... = ...\n return ...\n
Code \u00e0 trous Recherche de maximum
def recherche_max(tab):\n'''renvoie le maximum de la liste tab'''\n maxi = tab[0] \n for elt in tab:\n if ... > ...:\n maxi = ...\n return ...\n
"},{"location":"T4_Algorithmique/4.1_Extremums_et_moyennes/intro_cours/#2-algorithme-de-calcul-de-moyenne","title":"2. Algorithme de calcul de moyenne","text":"On cherche \u00e0 coder une fonction moyenne
qui prend en param\u00e8tre une liste tab
et qui renvoie la moyenne des \u00e9l\u00e9ments de cette liste.
Utilisation :
>>> moyenne([4, 3, 8, 1])\n 4.0\n
Code \u00e0 trous Recherche de maximum
def moyenne(tab):\n''' renvoie la moyenne de tab'''\n
Code \u00e0 trous Recherche de maximum
def moyenne(tab):\n''' renvoie la moyenne de tab'''\n ... = ...\n for ... in ...:\n ... += ...\n return ... / ...\n
Code \u00e0 trous Recherche de maximum
def moyenne(tab):\n''' renvoie la moyenne de tab'''\n somme = 0\n for elt in ...:\n ... += ...\n return ... / ...\n
Code \u00e0 trous Recherche de maximum
def moyenne(tab):\n''' renvoie la moyenne de tab'''\n somme = 0\n for elt in tab:\n somme += ...\n return ... / ...\n
"},{"location":"T4_Algorithmique/4.1_Extremums_et_moyennes/intro_cours/#3-algorithme-de-recherche-doccurrence","title":"3. Algorithme de recherche d'occurrence","text":"On cherche \u00e0 coder une fonction recherche_occurrence
qui prend en param\u00e8tre un \u00e9lement elt
et une liste tab
et qui renvoie la liste (\u00e9ventuellement vide) des indices de elt
dans tab
.
Utilisation :
>>> recherche_occurrence(3, [1, 6, 3, 8, 3, 2])\n[2, 4]\n>>> recherche_occurrence(7, [1, 6, 3, 8, 3, 2])\n[]\n
Code \u00e0 trous Recherche d'occurrence
def recherche_occurrence(elt, tab):\n''' renvoie la liste (\u00e9ventuellement vide)\n des indices de elt dans tab'''\n
Code \u00e0 trous Recherche d'occurrence
def recherche_occurrence(elt, tab):\n''' renvoie la liste (\u00e9ventuellement vide)\n des indices de elt dans tab'''\n ... = ...\n for ... in range(...):\n if ... == ...:\n ...\n return ...\n
Code \u00e0 trous Recherche d'occurrence
def recherche_occurrence(elt, tab):\n''' renvoie la liste (\u00e9ventuellement vide)\n des indices de elt dans tab'''\n liste_indices = ...\n for i in range(...):\n if ... == ...:\n ....append(i)\n return ...\n
Code \u00e0 trous Recherche d'occurrence
def recherche_occurrence(elt, tab):\n''' renvoie la liste (\u00e9ventuellement vide)\n des indices de elt dans tab'''\n liste_indices = []\n for i in range(len(tab)):\n if tab[i] == ...:\n ....append(i)\n return ...\n
"},{"location":"T4_Algorithmique/4.2_Complexite/cours/","title":"4.2 Complexit\u00e9 d'un algorithme","text":"La complexit\u00e9 d'un algorithme est une notion qui nous \u00e9claire sur la mani\u00e8re dont cet algorithme va \u00eatre sensible \u00e0 la taille des donn\u00e9es pass\u00e9es en param\u00e8tre. Il y a plusieurs types de complexit\u00e9s \u00e9tudiables (nombre d'op\u00e9rations, temps n\u00e9cessaire, espace-m\u00e9moire n\u00e9cessaire...).
En NSI, nous nous contenterons d'estimer (lorsque cela est possible) le nombre d'op\u00e9rations effectu\u00e9es par l'algorithme, et nous mesurerons les temps d'ex\u00e9cution de ces algortihmes.
Nous observerons surtout comment \u00e9volue ce temps d'ex\u00e9cution en fonction de la taille des donn\u00e9es pass\u00e9es en param\u00e8tre (la taille d'une liste, par exemple). Cela nous permettra dans ce cours de classer nos algorithmes en deux cat\u00e9gories : les algorithmes de complexit\u00e9 lin\u00e9aire et ceux de complexit\u00e9 quadratique.
"},{"location":"T4_Algorithmique/4.2_Complexite/cours/#1-complexite-lineaire","title":"1. Complexit\u00e9 lin\u00e9aire","text":""},{"location":"T4_Algorithmique/4.2_Complexite/cours/#11-exemple","title":"1.1 Exemple","text":"Exemple d'algorithme
Votre travail est de mettre des bulletins dans des enveloppes pour une campagne de communication. L'algorithme en jeu ici est \"je prends un bulletin, je le plie, je le mets dans l'enveloppe, je ferme l'enveloppe\".
On suppose que vous travaillez \u00e0 un rythme constant. Le premier jour, on vous donne \\(n\\) enveloppes \u00e0 remplir. Vous mettez un temps \\(T\\) pour les traiter. Le deuxi\u00e8me jour, suite \u00e0 l'absence d'un employ\u00e9, on vous donne le double d'enveloppes, soit \\(2n\\) enveloppes. Combien de temps allez vous mettre pour les traiter ?
R\u00e9ponseCela prendra deux fois plus de temps, donc \\(2T\\).
"},{"location":"T4_Algorithmique/4.2_Complexite/cours/#12-vocabulaire","title":"1.2 Vocabulaire","text":"On dit que l'algorithme ci-dessus est de complexit\u00e9 lin\u00e9aire.
Complexit\u00e9 lin\u00e9aire
Les expressions suivantes sont \u00e9quivalentes :
Toutes ces formulations renvoient \u00e0 la m\u00eame id\u00e9e : le nombre d'op\u00e9rations n\u00e9cessaires (et donc le temps n\u00e9cessaire \u00e0 la terminaison de l'algorithme) \u00e9volue proportionnellement avec le nombre de donn\u00e9es \u00e0 traiter.
"},{"location":"T4_Algorithmique/4.2_Complexite/cours/#13-formulation-mathematique","title":"1.3 Formulation math\u00e9matique","text":"Si un employ\u00e9 A met 3 secondes par enveloppe, on aura \\(T_A=3n\\). Si un employ\u00e9 B met 20 secondes par enveloppe, on aura \\(T_B=20n\\).
On retrouve la formulation math\u00e9matique d'une fonction lin\u00e9aire \\(f\\).
\\[f : x \\mapsto ax \\quad\\text{ , avec } a \\in \\mathbb{R}\\]Ici, la fonction \\(f_A\\) serait \\(f_A(x)=3x\\), la fonction \\(f_B\\) serait \\(f_B(x)=20x\\)
Dans les deux cas l'algorithme a la m\u00eame complexit\u00e9 (lin\u00e9aire donc). Ce qui compte est le fait que pour chacun des employ\u00e9s, avoir deux fois plus d'enveloppes prendrait deux fois plus de temps.
"},{"location":"T4_Algorithmique/4.2_Complexite/cours/#14-verification-experimentale","title":"1.4 V\u00e9rification exp\u00e9rimentale","text":"On consid\u00e8re la fonction ci-dessous :
def fabrique(n):\n liste = []\n for _ in range(n):\n liste.append(\"ok\")\n return liste\n
Le code ci-dessous va mesurer le temps d'ex\u00e9cution de cette fonction avec deux param\u00e8tres diff\u00e9rents : la valeur 400 puis la valeur 800.
import time\nt0 = time.time()\nlstA = fabrique(400)\nprint(\"temps pour une liste de taille 400 :\", time.time() - t0)\nt0 = time.time()\nlstB = fabrique(800)\nprint(\"temps pour une liste de taille 800 :\", time.time() - t0)\n
R\u00e9sultats de l'ex\u00e9cution :
temps pour une liste de taille 400 : 2.384185791015625e-05\ntemps pour une liste de taille 800 : 4.2438507080078125e-05\n
Interpr\u00e9tation : Doubler la taille du param\u00e8tre d'entr\u00e9e a eu pour effet de doubler (quasiment) le temps d'ex\u00e9cution. Cela semble indiquer que la complexit\u00e9 de cette fonction est lin\u00e9aire. En observant l'algorithme, nous pouvons confirmer cette supposition : le nombre d'op\u00e9rations de la boucle for
est \u00e9gal au param\u00e8tre n
, et est donc directement proportionnel \u00e0 la valeur de ce param\u00e8tre.
Exemple d'algorithme
Vous avez l'habitude de tondre la pelouse de votre terrain carr\u00e9, de c\u00f4t\u00e9 \\(n\\). Cela vous prend un certain temps \\(T\\). Votre voisin vous propose de venir chez lui tondre son terrain carr\u00e9 de c\u00f4t\u00e9 \\(2n\\). Combien de temps cela va-t-il vous prendre pour tondre le terrain de votre voisin ?
R\u00e9ponseCela vous prendra 4 fois plus de temps.
"},{"location":"T4_Algorithmique/4.2_Complexite/cours/#22-vocabulaire","title":"2.2 Vocabulaire","text":"On dit que l'algorithme ci-dessus est de complexit\u00e9 quadratique.
Complexit\u00e9 quadratique
Les expressions suivantes sont \u00e9quivalentes :
Toutes ces formulations renvoient \u00e0 la m\u00eame id\u00e9e : le nombre d'op\u00e9rations n\u00e9cessaires (et donc le temps n\u00e9cessaire \u00e0 la terminaison de l'algorithme) \u00e9volue proportionnellement avec le carr\u00e9 du nombre de donn\u00e9es \u00e0 traiter.
Les algorithmes quadratiques sont moins \u00abint\u00e9ressants\u00bb que les algorithmes lin\u00e9aires, car ils vont consommer beaucoup plus de ressources. Lors de l'\u00e9laboration d'un algorithme, on va toujours essayer de trouver l'algorithme ayant la complexit\u00e9 la plus faible possible.
"},{"location":"T4_Algorithmique/4.2_Complexite/cours/#23-verification-experimentale","title":"2.3 V\u00e9rification exp\u00e9rimentale","text":"On consid\u00e8re la fonction ci-dessous :
def tables(n):\n for a in range(n):\n for b in range(n):\n c = a * b\n
Le code ci-dessous va mesurer le temps d'ex\u00e9cution de cette fonction avec deux param\u00e8tres diff\u00e9rents : la valeur 100 puis la valeur 200.
import time\nt0 = time.time()\ntables(100)\nprint(\"temps pour n = 100 :\", time.time() - t0)\nt0 = time.time()\ntables(200)\nprint(\"temps pour n = 200 : \", time.time() - t0)\n
R\u00e9sultats de l'ex\u00e9cution :
temps pour n = 100 : 0.0003533363342285156\ntemps pour n = 200 : 0.0014693737030029297\n
Interpr\u00e9tation : Doubler la taille du param\u00e8tre d'entr\u00e9e a eu pour effet de quadrupler le temps d'ex\u00e9cution. Cela semble indiquer que la complexit\u00e9 de cette fonction est quadratique, car \\(2^2=4\\).
En observant l'algorithme, nous pouvons confirmer cette supposition : le nombre d'op\u00e9rations des deux boucles for
est \u00e9gal \u00e0 n^2
.
Il peut arriver (mais c'est rare) que la complexit\u00e9 d'un algorithme soit ind\u00e9pendante de la taille des donn\u00e9es \u00e0 traiter. Dans ce cas, c'est souvent une tr\u00e8s bonne nouvelle.
Observons l'acc\u00e8s au 1er \u00e9l\u00e9ment d'une liste :
Complexit\u00e9 constante
Les expressions suivantes sont \u00e9quivalentes :
Toutes ces formulations renvoient \u00e0 la m\u00eame id\u00e9e : le nombre d'op\u00e9rations n\u00e9cessaires (et donc le temps n\u00e9cessaire \u00e0 la terminaison de l'algorithme) est constant quelle que soit la taille des donn\u00e9es d'entr\u00e9e de l'algorithme.
"},{"location":"T4_Algorithmique/4.3_Tri_par_insertion/cours/","title":"4.3 Tri par insertion","text":""},{"location":"T4_Algorithmique/4.3_Tri_par_insertion/cours/#0-introduction","title":"0. Introduction","text":"Activit\u00e9 d'introduction
"},{"location":"T4_Algorithmique/4.3_Tri_par_insertion/cours/#1-tri-par-insertion-version-la-plus-intuitive","title":"1. Tri par insertion (version la plus intuitive)","text":""},{"location":"T4_Algorithmique/4.3_Tri_par_insertion/cours/#11-principe-et-algorithme","title":"1.1 Principe et algorithme","text":"Consid\u00e9rons la liste [7, 5, 2, 8, 1, 4]
Voici le fonctionnement de l'algorithme :
Explications :
Algorithme :
Pour toutes les valeurs, en commen\u00e7ant par la deuxi\u00e8me :
Tri par insertion (version simple)
def tri_insertion(lst):\n'''trie en place la liste lst donn\u00e9e en param\u00e8tre'''\n for i in range(1, len(lst)): #(1)\n k = i #(2)\n while k > 0 and lst[k-1] > lst[k] : #(3)\n lst[k], lst[k-1] = lst[k-1], lst[k] #(4) \n k = k - 1 #(5) \n
i
en une variable k
. On se positionne sur l'\u00e9l\u00e9ment d'indice k
. On va faire \u00abreculer\u00bb cet \u00e9l\u00e9ment tant que c'est possible. On ne touche pas \u00e0 i
. k - 1
. La boucle peut continuer.Application :
>>> maliste = [7, 5, 2, 8, 1, 4]\n>>> tri_insertion(maliste)\n>>> maliste\n[1, 2, 4, 5, 7, 8]\n
"},{"location":"T4_Algorithmique/4.3_Tri_par_insertion/cours/#2-tri-par-insertion-version-optimisee","title":"2. Tri par insertion (version optimis\u00e9e)","text":""},{"location":"T4_Algorithmique/4.3_Tri_par_insertion/cours/#21-principe-et-algorithme","title":"2.1 Principe et algorithme","text":"Observez l'animation ci-dessous et comparer avec la version initiale.
Tri par insertion (version optimis\u00e9e)
def tri_insertion_v2(lst) :\n'''trie en place la liste lst donn\u00e9e en param\u00e8tre'''\n for i in range(1, len(lst)): # (1)\n cle = lst[i] # (2)\n k = i - 1 # (3)\n while k >= 0 and lst[k] > cle : # (4)\n lst[k + 1] = lst[k] # (5)\n k = k -1 # (6)\n lst[k + 1] = cle # (7)\n
cle
notre valeur de travailApplication :
>>> maliste = [7, 5, 2, 8, 1, 4]\n>>> tri_insertion_v2(maliste)\n>>> maliste\n[1, 2, 4, 5, 7, 8]\n
"},{"location":"T4_Algorithmique/4.3_Tri_par_insertion/cours/#3-complexite-de-lalgorithme","title":"3. Complexit\u00e9 de l'algorithme","text":""},{"location":"T4_Algorithmique/4.3_Tri_par_insertion/cours/#31-etude-experimentale","title":"3.1 \u00c9tude exp\u00e9rimentale","text":"Lire le cours sur la complexit\u00e9 et proposer des mesures exp\u00e9rimentales pour d\u00e9terminer la complexit\u00e9 du tri par insertion.
"},{"location":"T4_Algorithmique/4.3_Tri_par_insertion/cours/#32-demonstration","title":"3.2 D\u00e9monstration","text":"D\u00e9nombrons le nombre d'op\u00e9rations dans le pire des cas, pour une liste de taille \\(n\\).
for
: elle s'ex\u00e9cute \\(n-1\\) fois.while
: dans le pire des cas, elle ex\u00e9cute d'abord 1 op\u00e9ration, puis 2, puis 3... jusqu'\u00e0 \\(n-1\\). Or Le terme de plus haut degr\u00e9 de l'expression \\(\\dfrac{n \\times (n-1)}{2}\\) est de degr\u00e9 2 : le nombre d'op\u00e9rations effectu\u00e9es est donc proportionnel au carr\u00e9 de la taille des donn\u00e9es d'entr\u00e9e. Ceci d\u00e9montre que le tri par insertion est de complexit\u00e9 quadratique.
Dans le cas (rare, mais il faut l'envisager) o\u00f9 la liste est d\u00e9j\u00e0 tri\u00e9e, on ne rentre jamais dans la boucle while
: le nombre d'op\u00e9rations est dans ce cas \u00e9gal \u00e0 \\(n-1\\), ce qui caract\u00e9rise une complexit\u00e9 lin\u00e9aire.
Est-on s\u00fbr que notre algorithme va s'arr\u00eater ? Le programme est constitu\u00e9 d'une boucle while
imbriqu\u00e9e dans une boucle for
. Seule la boucle while
peut provoquer une non-terminaison de l'algorithme. Observons donc ses conditions de sortie :
while k >= 0 and l[k] > cle :\n
La condition l[k] > cle
ne peut pas \u00eatre rendue fausse avec certitude. Par contre, la condition k >= 0
sera fausse d\u00e8s que la variable k
deviendra n\u00e9gative. Or la ligne k = k - 1
nous assure que la variable k
diminuera \u00e0 chaque tour de boucle. La condition k >= 0
deviendra alors forc\u00e9ment fausse au bout d'un certain temps.
Nous avonc donc prouv\u00e9 la terminaison de l'algorithme.
Vocabulaire
On dit que la valeur k
est un variant de boucle. C'est une notion th\u00e9orique (ici illustr\u00e9e de mani\u00e8re simple par la valeur k
) qui permet de prouver la bonne sortie d'une boucle et donc la terminaison d'un algorithme.
Les preuves de correction sont des preuves th\u00e9oriques. La preuve ici s'appuie sur le concept math\u00e9matique de r\u00e9currence. Principe du raisonnement par r\u00e9currence : une propri\u00e9t\u00e9 \\(P(n)\\) est vraie si :
Ici, la propri\u00e9t\u00e9 serait : \u00ab Quand \\(k\\) varie entre 0 et longueur(liste) -1
, la sous-liste de longueur \\(k\\) est tri\u00e9e dans l'ordre croissant.\u00bb
Vocabulaire
On appelle cette propri\u00e9t\u00e9 un invariant de boucle. Invariant siginifie qu'elle reste vraie pour chaque boucle.
def tri_insertion(lst):\n'''trie en place la liste lst donn\u00e9e en param\u00e8tre'''\n
Code \u00e0 trous def tri_insertion(lst):\n'''trie en place la liste lst donn\u00e9e en param\u00e8tre'''\n for i in range(..., ...): \n ... = ... \n while ... > ... and ... > ... : \n ..., ... = ..., ... \n ... = ... \n
Code \u00e0 trous def tri_insertion(lst):\n'''trie en place la liste lst donn\u00e9e en param\u00e8tre'''\n for i in range(..., len(lst)): \n k = ... \n while k > ... and lst[...] > lst[...] : \n lst[...], lst[...] = lst[...], lst[...] \n k = ... \n
Code \u00e0 trous def tri_insertion(lst):\n'''trie en place la liste lst donn\u00e9e en param\u00e8tre'''\n for i in range(1, len(lst)): \n k = ... \n while k > ... and lst[k-1] > lst[k] : \n lst[k], lst[k-1] = lst[...], lst[...] \n k = ... \n
"},{"location":"T4_Algorithmique/4.4_Tri_par_selection/cours/","title":"4.4 Tri par s\u00e9lection","text":""},{"location":"T4_Algorithmique/4.4_Tri_par_selection/cours/#0-preambule","title":"0. Pr\u00e9ambule","text":"Pourquoi \u00e9tudier des algorithmes de tri ? Autant ne pas le cacher, ces algorithmes sont d\u00e9j\u00e0 impl\u00e9ment\u00e9s (quelque soit le langage) dans des fonctions tr\u00e8s performantes.
En Python, on utilise la fonction sort()
:
>>> tab = [4, 8, 1, 2, 6]\n>>> tab.sort()\n>>> tab\n[1, 2, 4, 6, 8]\n
Le meilleur de nos futurs algorithmes de tri sera moins efficace que celui de cette fonction sort()
... Malgr\u00e9 cela, il est essentiel de se confronter \u00e0 l'\u00e9laboration manuelle d'un algorithme de tri. Le tri par s\u00e9lection est le premier des deux algorithmes de tri que nous allons \u00e9tudier (nous \u00e9tudierons aussi le tri par insertion). Ces deux algorithmes ont pour particularit\u00e9 de :
Activit\u00e9 d'introduction
"},{"location":"T4_Algorithmique/4.4_Tri_par_selection/cours/#1-animation","title":"1. Animation","text":"Consid\u00e9rons la liste [5, 4, 2, 1]
Voici le fonctionnement de l'algorithme :
"},{"location":"T4_Algorithmique/4.4_Tri_par_selection/cours/#2-principe","title":"2. Principe","text":"
Comme dans tous les autres algorithmes de tri que nous allons \u00e9tudier, nous allons travailler en place. Cela signifie que nous ne travaillons que sur la liste initiale, sans en cr\u00e9er de nouvelles. Le tri sera fait en permutant des \u00e9l\u00e9ments.
Tr\u00e8s tr\u00e8s grossi\u00e8rement, l'id\u00e9e de l'algorithme est la suivante :
Pour r\u00e9aliser ceci, le travail va se faire en manipulant les indices des \u00e9l\u00e9ments de la liste.
Description de l'algorithme
Le travail se fait essentiellement sur les indices.
Tri par s\u00e9lection
def tri_selection(lst) :\n for i in range(len(lst)-1):\n indice_min = i\n for k in range(i+1, len(lst)) :\n if lst[k] < lst[indice_min]:\n indice_min = k\n lst[i], lst[indice_min] = lst[indice_min], lst[i]\n
V\u00e9rification :
>>> ma_liste = [7, 5, 2, 8, 1, 4]\n>>> tri_selection(ma_liste)\n>>> ma_liste\n[1, 2, 4, 5, 7, 8]\n
"},{"location":"T4_Algorithmique/4.4_Tri_par_selection/cours/#4-complexite-de-lalgorithme","title":"4. Complexit\u00e9 de l'algorithme","text":""},{"location":"T4_Algorithmique/4.4_Tri_par_selection/cours/#40-de-quoi-parle-t-on","title":"4.0. De quoi parle-t-on ?","text":"Cours sur la complexit\u00e9
"},{"location":"T4_Algorithmique/4.4_Tri_par_selection/cours/#41-calcul-du-nombre-doperations","title":"4.1. Calcul du nombre d'op\u00e9rations","text":"La ligne 3 indice_min = i
va s'ex\u00e9cuter \\(n\\) fois. Mais int\u00e9ressons-nous \u00e0 la ligne 5 (le test) : combien de fois va-t-elle s'ex\u00e9cuter ? \u00c0 chaque tour de la premi\u00e8re boucle (qui en comporte \\(n\\)), le nombre d'op\u00e9rations de la 2\u00e8me boucle va varier :
Or \\(1+2+3+\\dots+n-1=\\dfrac{n \\times (n-1)}{2}= \\dfrac{1}{2}n^2 - \\dfrac{1}{2}n\\)
Dans cette expression, un terme joue un r\u00f4le fondamental : \\(n^2\\). C'est le terme pr\u00e9pond\u00e9rant (le terme de plus haut degr\u00e9), qui va \u00e0 lui seul caract\u00e9riser la mani\u00e8re dont le nombre d'op\u00e9rations \u00e9volue en fonction de \\(n\\).
Ici, \\(n\\) est \u00e9lev\u00e9 au carr\u00e9, ce qui signifie que le nombre d'op\u00e9rations va \u00e9voluer avec le carr\u00e9 du nombre de termes de la liste \u00e0 trier.
Complexit\u00e9 du tri par s\u00e9lection
Le tri par s\u00e9lection a une complexit\u00e9 quadratique.
"},{"location":"T4_Algorithmique/4.4_Tri_par_selection/cours/#42-influence-de-la-taille-de-la-liste-sur-le-temps-dexecution","title":"4.2 Influence de la taille de la liste sur le temps d'ex\u00e9cution","text":"Consid\u00e9rons qu'une liste de taille \\(n\\) est tri\u00e9e par l'algorithme de tri par s\u00e9lection en un temps \\(T\\). Le temps d'ex\u00e9cution d\u00e9pendant du nombre d'op\u00e9rations \u00e0 traiter, il va \u00e9voluer avec le carr\u00e9 de la taille de la liste.
Voici donc un ordre de grandeur de ce que devraient \u00eatre les temps n\u00e9cessaires pour trier une liste de taille \\(2n\\) ou \\(10n\\).
Taille de la liste Temps \\(n\\) \\(T\\) \\(2n\\) \\(4T\\) \\(10n\\) \\(100T\\)"},{"location":"T4_Algorithmique/4.4_Tri_par_selection/cours/#43-verification-experimentale","title":"4.3 V\u00e9rification exp\u00e9rimentale","text":"Exercice
\u00c9nonc\u00e9CorrectionAnalyser le code suivant :
import time\n\ndef tri_selection(lst):\n for i in range(len(lst)-1):\n i_min = i\n for k in range(i, len(lst)):\n if lst[k] < lst[i_min]:\n i_min = k\n lst[i_min], lst[i] = lst[i], lst[i_min]\n\n\ndef mesures(n):\n total_temps = 0\n for _ in range(5):\n lst = list(range(n, 0, -1)) # (1)\n t0 = time.time()\n tri_selection(lst)\n delta_t = time.time() - t0\n total_temps += delta_t\n tps_moy = total_temps / 5\n print(f\"temps moyen pour trier une liste de taille {n} : {tps_moy}\")\n
Q1. Essayer de confirmer les r\u00e9sultats th\u00e9oriques du tableau pr\u00e9c\u00e9dent. On pourra travailler par exemple avec une liste initiale de taille 1000.
Q2. Recommencer avec une liste d\u00e9j\u00e0 tri\u00e9e. Que constate-t-on ?
Q1.
>>> mesures(10**3)\ntemps moyen pour trier une liste de taille 1000 : 0.03579235076904297\n>>> mesures(2*10**3)\ntemps moyen pour trier une liste de taille 2000 : 0.13821134567260743\n>>> mesures(10**4)\ntemps moyen pour trier une liste de taille 10000 : 3.3528685569763184\n
On retrouve (\u00e0 peu pr\u00e8s, mais plut\u00f4t bien) le facteur 4 quand la taille de la liste double, et le facteur 100 quand la taille de la liste est multipli\u00e9e par 10.
Q2. Changeons la ligne lst = list(range(n, 0, -1))
en lst = list(range(n))
:
>>> mesures(10**3)\ntemps moyen pour trier une liste de taille 1000 : 0.038380765914916994\n>>> mesures(2*10**3)\ntemps moyen pour trier une liste de taille 2000 : 0.13413033485412598\n>>> mesures(10**4)\ntemps moyen pour trier une liste de taille 10000 : 3.213682508468628\n
Les mesures sont identiques : l'\u00e9tat initial de la liste n'a pas d'influence.
"},{"location":"T4_Algorithmique/4.4_Tri_par_selection/cours/#5-preuve-de-la-terminaison-de-lalgorithme","title":"5.\u00a0Preuve de la terminaison de l'algorithme","text":"Est-on s\u00fbr que notre algorithme va s'arr\u00eater ?
\u00c0 l'observation du programme, constitu\u00e9 de deux boucles for
imbriqu\u00e9es, il n'y a pas d'ambigu\u00eft\u00e9 : on ne peut pas rentrer dans une boucle infinie. Le programme s'arr\u00eate forc\u00e9ment au bout de d'un nombre fixe d'op\u00e9rations. D'apr\u00e8s nos calculs sur la complexit\u00e9, ce nombre de tours de boucles est \u00e9gal \u00e0 \\(\\dfrac{n \\times (n-1)}{2}\\).
Ceci prouve que l'algorithme se terminera.
"},{"location":"T4_Algorithmique/4.4_Tri_par_selection/cours/#6-preuve-de-la-correction-de-lalgorithme","title":"6. Preuve de la correction de l'algorithme","text":"Est-on s\u00fbr que notre algorithme va bien trier notre liste ?
Les preuves de correction sont des preuves th\u00e9oriques. La preuve ici s'appuie sur le concept math\u00e9matique de r\u00e9currence. Principe du raisonnement par r\u00e9currence : une propri\u00e9t\u00e9 \\(P(n)\\) est vraie si :
Ici, la propri\u00e9t\u00e9 serait : \u00ab Quand \\(k\\) varie entre 0 et longueur(liste) -1
, la sous-liste de longueur \\(k\\) est tri\u00e9e dans l'ordre croissant.\u00bb On appelle cette propri\u00e9t\u00e9 un invariant de boucle (sous-entendu : elle est vraie pour chaque boucle)
Une jolie animation permettant de comparer les tris : (on peut y constater que le tri par s\u00e9lection met toujours autant de temps pour trier la liste, quelque soit son \u00e9tat initial)
Issue de ce site.
"},{"location":"T4_Algorithmique/4.4_Tri_par_selection/intro_cours/","title":"Vers le tri par s\u00e9lection","text":"Code \u00e0 trousdef tri_selection(lst) :\n ...\n
Code \u00e0 trous def tri_selection(lst) :\n for ... in ... :\n ... = ...\n for ... in ... :\n if ... :\n ...\n ...\n
Code \u00e0 trous def tri_selection(lst) :\n for i in range(...):\n ... = i\n for k in range(..., ...) :\n if ... < ... :\n ... = ...\n ..., ... = ..., ...\n
Code \u00e0 trous def tri_selection(lst) :\n for i in range(len(lst)-1):\n indice_min = ...\n for k in range(..., len(lst)) :\n if lst[...] < lst[...]:\n indice_min = ...\n lst[...], lst[...] = lst[...], lst[...]\n
"},{"location":"T4_Algorithmique/4.5_Dichotomie/cours/","title":"4.5 Dichotomie","text":"ou comment rechercher efficacement dans une liste tri\u00e9e ?
\u00abdichotomie\u00bb se dit en anglais binary search.
"},{"location":"T4_Algorithmique/4.5_Dichotomie/cours/#1-introduction-recherche-dune-valeur-dans-une-liste","title":"1. Introduction : recherche d'une valeur dans une liste","text":""},{"location":"T4_Algorithmique/4.5_Dichotomie/cours/#11-preambule","title":"1.1 Pr\u00e9ambule","text":"De l'importance de bien ranger ses affaires
Les premiers algorithmes \u00abc\u00e9l\u00e8bres\u00bb que nous avons d\u00e9couverts \u00e9taient des algorithmes de tri.
Quel est l'int\u00e9r\u00eat de trier ses donn\u00e9es ?
l'int\u00e9r\u00eat imm\u00e9diat est d'en tirer un classement : quelle est la plus grande (ou plus petite) valeur, la deuxi\u00e8me, la troisi\u00e8me... On s'en sert donc \u00e9videmment pour d\u00e9terminer une valeur optimale, un gagnant dans une comp\u00e9tition, etc. Mais il y a une autre raison plus importante.
Trier ses donn\u00e9es permet de rechercher plus rapidement une valeur pr\u00e9cise parmi celles-ci.
Exemple : pouvez-vous deviner la couleur \u00e0 laquelle je pense ?
coul = [\"bleu\", \"jaune\", \"rouge\", \"vert\", \"violet\", \"marron\"]\n
Toutes les m\u00e9thodes (proposition des valeurs dans l'ordre, au hasard, dans l'ordre inverse...) sont \u00e9quivalentes : elles sont toutes aussi mauvaises, aucune strat\u00e9gie n'est possible car les donn\u00e9es ne sont pas tri\u00e9es. Si je suis \u00e0 la recherche de la valeur \"vert\", le fait de piocher \"rouge\" ne me donnera aucune indication sur le fait que je devrais chercher plus \u00e0 gauche \u00e0 plus \u00e0 droite que l'endroit o\u00f9 j'ai pioch\u00e9.
Il faudrait pour cela que la liste soit tri\u00e9e (et donc qu'elle soit \u00abtriable\u00bb, ce qui n'est pas toujours le cas !). C'est donc le cas dans lequel nous allons nous placer dans toute la suite de ce cours :
Dans toute la suite, nous rechercherons un \u00e9l\u00e9ment dans une liste d'entiers tri\u00e9e dans l'ordre croissant.
"},{"location":"T4_Algorithmique/4.5_Dichotomie/cours/#12-contexte-de-recherche","title":"1.2 Contexte de recherche","text":"Consid\u00e9rons donc la liste lst
suivante :
lst = [2, 3, 6, 7, 11, 14, 18, 19, 24]\n
L'objectif est de d\u00e9finir un algorithme de recherche efficace d'une valeur arbitraire pr\u00e9sente dans cette liste.
"},{"location":"T4_Algorithmique/4.5_Dichotomie/cours/#13-methode-naive-recherche-par-balayage","title":"1.3 M\u00e9thode na\u00efve : recherche par balayage","text":"C'est la m\u00e9thode la plus intuitive : on essaie toutes les valeurs (par exemple, dans l'ordre croissant) jusqu'\u00e0 trouver la bonne.
Exercice 1
\u00c9nonc\u00e9Correction\u00c9crire un code permettant d'afficher l'indice de la valeur 14
dans la liste lst = [2, 3, 6, 7, 11, 14, 18, 19, 24]
.
lst = [2, 3, 6, 7, 11, 14, 18, 19, 24]\nfor k in range(len(lst)):\n if lst[k] == 14 :\n print(k)\n
Exercice 2
\u00c9nonc\u00e9Correction\u00c9crire une fonction trouve
qui re\u00e7oit pour param\u00e8tres une liste lst
et un nombre val
et qui renvoie l'indice de val
dans la liste lst
. Si la valeur val
n'est pas trouv\u00e9e, on renverra \"non trouv\u00e9\"
.
def trouve(val, lst) :\n for k in range(len(lst)) :\n if lst[k] == val:\n return k\n return \"non trouv\u00e9\"\n
"},{"location":"T4_Algorithmique/4.5_Dichotomie/cours/#13-complexite-de-la-methode-naive","title":"1.3 Complexit\u00e9 de la m\u00e9thode na\u00efve","text":"Complexit\u00e9 de la m\u00e9thode na\u00efve
Dans le cas d'une recherche na\u00efve, le nombre (maximal) d'op\u00e9rations n\u00e9cessaires est proportionnel \u00e0 la taille de la liste \u00e0 \u00e9tudier. Si on appelle \\(n\\) la longueur de la liste, on dit que cet algorithme est d'ordre \\(n\\), ou lin\u00e9aire, ou en \\(O(n)\\).
Remarque : La m\u00e9thode na\u00efve n'utilise pas le fait que la liste est tri\u00e9e, on aurait pu aussi bien l'utiliser sur une liste non tri\u00e9e.
"},{"location":"T4_Algorithmique/4.5_Dichotomie/cours/#2-recherche-dichotomique","title":"2. Recherche dichotomique","text":""},{"location":"T4_Algorithmique/4.5_Dichotomie/cours/#21-introduction-le-jeu-du-devine-un-nombre-entre-1-et-100","title":"2.1 Introduction : le jeu du \u00abdevine un nombre entre 1 et 100\u00bb","text":"R\u00e8gles du jeu
Si je choisis un nombre entre 1 et 100, quelle est la strat\u00e9gie optimale pour deviner ce nombre le plus vite possible ? (\u00e0 chaque \u00e9tape, une indication (trop grand, trop petit) permet d'affiner la proposition suivante)
R\u00e9ponse attendue : la meilleure strat\u00e9gie est de couper en deux \u00e0 chaque fois l'intervalle d'\u00e9tude. On d\u00e9marre de 50, puis 75 ou 25, etc.
Il convient toute fois de remettre en question cette m\u00e9thode qui para\u00eet naturellement optimale : si je propose 90 comme nombre de d\u00e9part, j'ai certes moins de chance que le nombre soit entre 90 et 100, mais s'il l'est, j'ai gagn\u00e9 un gros avantage car mon nouvel intervalle est tr\u00e8s r\u00e9duit.
Notion d'esp\u00e9rance probabilisteD\u00e9terminer si un risque vaut la peine d'\u00eatre pris passe par la compr\u00e9hension de la notion d'esp\u00e9rance probabiliste. Exemple : \"On lance un d\u00e9, s'il tombe sur le 6 vous recevez 8 euros, sinon vous me donnez 1 euro. Voulez-vous jouer ?\"
\\(E(X) = 8 \\times \\frac{1}{6} + (-1) \\times \\frac{5}{6} = \\frac{8}{6}-\\frac{5}{6}=\\frac12\\)
En moyenne, on gagnera 50 centimes par partie, il faut donc jouer.
Le graphique ci-dessous repr\u00e9sente le nombre de coups moyens (sur 10 000 parties simul\u00e9es)
Interpr\u00e9tations et remarques
La strat\u00e9gie optimale est de diviser en deux \u00e0 chaque \u00e9tape l'intervalle d'\u00e9tude. On appelle cela une m\u00e9thode par dichotomie, du grec ancien \u03b4\u03b9\u03c7\u03bf\u03c4\u03bf\u03bc\u03af\u03b1, dikhotomia (\u00ab division en deux parties \u00bb).
"},{"location":"T4_Algorithmique/4.5_Dichotomie/cours/#22-algorithme-de-recherche-dichotomique","title":"2.2 Algorithme de recherche dichotomique","text":"Dichotomie, d\u00e9roulement intuitif
Comprendre la m\u00e9thode de dichotomie est relativement simple, mais savoir la programmer est plus difficile.
Pour des raisons d'efficacit\u00e9, nous allons garder intacte notre liste de travail et simplement faire \u00e9voluer les indices qui d\u00e9terminent le d\u00e9but et la fin de notre liste.
Une autre m\u00e9thode pourrait \u00eatre d'extraire \u00e0 chaque \u00e9tape une nouvelle liste (dont on esp\u00e8re qu'elle contient la valeur cherch\u00e9e), mais la technique utilis\u00e9e (le slicing de liste) consomme beaucoup trop de ressources.
Nous allons donc travailler avec trois variables :
indice_debut
(en bleu sur le sch\u00e9ma)indice_fin
(en bleu sur le sch\u00e9ma)indice_central
, qui est \u00e9gale \u00e0 (indice_debut + indice_fin) // 2
(en rouge sur le sch\u00e9ma) Nous allons faire se rapprocher les indices indice_debut
et indice_fin
tant que indice_debut <= indice_fin
Codes \u00e0 trous
Recherche dichotomique dans une liste tri\u00e9e
def recherche_dichotomique(lst, val) :\n indice_debut = 0\n indice_fin = len(lst) - 1\n while indice_debut <= indice_fin :\n indice_centre = (indice_debut + indice_fin) // 2 \n valeur_centrale = lst[indice_centre] \n if valeur_centrale == val : \n return indice_centre\n if valeur_centrale < val : \n indice_debut = indice_centre + 1\n else :\n indice_fin = indice_centre - 1\n return None\n
Utilisation
>>> mylist = [2, 3, 6, 7, 11, 14, 18, 19, 24]\n>>> recherche_dichotomique(mylist, 14)\n5\n>>> recherche_dichotomique(mylist, 2)\n0\n>>> recherche_dichotomique(mylist, 24)\n8\n>>> recherche_dichotomique(mylist, 2022)\n>>> \n
"},{"location":"T4_Algorithmique/4.5_Dichotomie/cours/#24-visualisations-avec-pythontutor","title":"2.4 Visualisations avec PythonTutor","text":"Cas o\u00f9 la valeur est trouv\u00e9e
Cas o\u00f9 la valeur N'est PAS trouv\u00e9e
"},{"location":"T4_Algorithmique/4.5_Dichotomie/cours/#25-terminaison-de-lalgorithme","title":"2.5 Terminaison de l'algorithme","text":"
Est-on s\u00fbr que l'algorithme va se terminer ? La boucle while
qui est utilis\u00e9e doit nous inciter \u00e0 la prudence (voir cours sur la boucle While). Il y a en effet le risque de rentrer dans une boucle infinie. Pourquoi n'est-ce pas le cas ?
Aide : observer la position des deux fl\u00e8ches bleues lors de l'ex\u00e9cution de l'algorithme
La condition de la boucle while
est indice_debut <= indice_fin
, qui pourrait aussi s'\u00e9crire indice_fin >= indice_debut
. Au d\u00e9marrage de la boucle, on a :
indice_debut = 0\n indice_fin = len(L) - 1\n
Ceci qui nous assure donc de bien rentrer dans la boucle.
Ensuite, \u00e0 chaque \u00e9tape :
indice_debut
augmente strictement (gr\u00e2ce \u00e0 indice_debut = indice_centre + 1
)indice_fin
diminue strictement (gr\u00e2ce \u00e0 indice_fin = indice_centre - 1
)Il va donc forc\u00e9ment arriver un moment o\u00f9 indice_fin
sera inf\u00e9rieur \u00e0 indice_debut
: on sortira alors de la boucle et le programme va bien se terminer.
Variant de boucle On dit que la valeur indice_fin - indice_debut
repr\u00e9sente le variant de boucle de cet algorithme. Ce variant est un nombre entier, d'abord strictement positif, puis qui va d\u00e9cro\u00eetre jusqu'\u00e0 la valeur 0.
Combien d'\u00e9tapes (au maximum) sont-elles n\u00e9cessaires pour arriver \u00e0 la fin de l'algorithme ? Imaginons que la liste initiale poss\u00e8de 8 valeurs. Apr\u00e8s une \u00e9tape, il ne reste que 4 valeurs \u00e0 traiter. Puis 2 valeurs. Puis une seule valeur. Il y a donc 3 \u00e9tapes avant de trouver la valeur cherch\u00e9e.
Exercice
\u00c9nonc\u00e9Conclusion :
C'est le nombre de puissances de 2 que contient le nombre \\(N\\) de termes de la liste qui est d\u00e9terminant dans la complexit\u00e9 de l'algorithme.
Ce nombre s'appelle le logarithme de base 2 et se note \\(\\log_2(N)\\).
On dit que l'algorithme de dichotomie a une vitesse logarithmique. On rencontrera parfois la notation \\(O(\\log_2(n))\\).
Complexit\u00e9 de la dichotomie
La recherche dichotomique se fait avec une complexit\u00e9 logarithmique.
Cette complexit\u00e9 est bien meilleure qu'une complexit\u00e9 lin\u00e9aire. Le nombre d'op\u00e9rations \u00e0 effectuer est tr\u00e8s peu sensible \u00e0 la taille des donn\u00e9es d'entr\u00e9e, ce qui en fait un algorithme tr\u00e8s efficace.
"},{"location":"T4_Algorithmique/4.5_Dichotomie/cours/#3-experiences-et-comparaison-des-vitesses-dexecution","title":"3. Exp\u00e9riences et comparaison des vitesses d'ex\u00e9cution","text":""},{"location":"T4_Algorithmique/4.5_Dichotomie/cours/#avec-une-liste-contenant-100-000-valeurs","title":"Avec une liste contenant 100 000 valeurs","text":"# cette ligne de code permet de transformer le contenu du fichier input_centmille.txt\n# en une liste L de 100 000 valeurs.\n\nL = open(\"data/input_centmille.txt\",'r').read().split('\\n')\n
Mesurons le temps n\u00e9cessaire pour trouver l'indice de la derni\u00e8re valeur de la liste (qui est 299474) avec la m\u00e9thode de balayage (m\u00e9thode 1) :
%timeit trouve(L, 299474)\n
4.43 ms \u00b1 86.1 \u00b5s per loop (mean \u00b1 std. dev. of 7 runs, 100 loops each)\n
Mesurons le temps n\u00e9cessaire pour trouver l'indice de la derni\u00e8re valeur de la liste (qui est 299474) avec la m\u00e9thode par dichotomie (m\u00e9thode 2) :
%timeit trouve_dicho(L, 299474)\n
3.21 \u00b5s \u00b1 19.6 ns per loop (mean \u00b1 std. dev. of 7 runs, 100000 loops each)\n
Comparaison des deux m\u00e9thodes : l'algorithme dichotomique est bien plus rapide que l'algorithme de balayage (la diff\u00e9rence d'ordre de grandeur est de \\(10^3\\), qui correspond bien \u00e0 l'ordre de grandeur de \\(\\frac{n}{\\log(n)}\\) lorsque \\(n\\) vaut \\(10^5\\)).
"},{"location":"T4_Algorithmique/4.5_Dichotomie/cours/#avec-une-liste-contenant-1-000-000-valeurs-soit-10-fois-plus-que-la-liste-precedente","title":"Avec une liste contenant 1 000 000 valeurs (soit 10 fois plus que la liste pr\u00e9c\u00e9dente)","text":"# ce code permet de transformer le contenu du fichier million.txt en une liste L de 1 000 000 valeurs.\nf = open(\"data/input_million.txt\",'r')\nl = f.readlines()\nL = []\nfor k in l :\n L.append(int(k[:-1]))\n
Mesurons le temps n\u00e9cessaire pour trouver l'indice de la derni\u00e8re valeur de la liste (qui est 2999306) avec la m\u00e9thode de balayage (m\u00e9thode 1) :
%timeit trouve(L, 2999306)\n
46.9 ms \u00b1 615 \u00b5s per loop (mean \u00b1 std. dev. of 7 runs, 10 loops each)\n
Mesurons le temps n\u00e9cessaire pour trouver l'indice de la derni\u00e8re valeur de la liste (qui est 2999306) avec la m\u00e9thode par dichotomie (m\u00e9thode 2) :
%timeit trouve_dicho(L, 2999306)\n
3.04 \u00b5s \u00b1 39.4 ns per loop (mean \u00b1 std. dev. of 7 runs, 100000 loops each)\n
Comparaison des deux m\u00e9thodes : l'algorithme dichotomique est toujours bien plus rapide que l'algorithme de balayage (la diff\u00e9rence d'ordre de grandeur est de \\(10^4\\), qui correspond bien \u00e0 l'ordre de grandeur de \\(\\frac{n}{\\log(n)}\\) lorsque \\(n\\) vaut \\(10^6\\)).
"},{"location":"T4_Algorithmique/4.5_Dichotomie/cours/#influence-de-la-taille-de-la-liste-sur-la-vitesse-de-chaque-methode","title":"Influence de la taille de la liste sur la vitesse de chaque m\u00e9thode :","text":"Remarque : Il ne faut toutefois pas oublier que la m\u00e9thode dichotomique, bien plus rapide, n\u00e9cessite que la liste ait \u00e9t\u00e9 auparavant tri\u00e9e. Ce qui rajoute du temps de calcul ! (cf tri par insertion ou tri par s\u00e9lection )
"},{"location":"T4_Algorithmique/4.5_Dichotomie/intro_cours/","title":"Vers la recherche dichotomique","text":"Code \u00e0 trousdef recherche_dichotomique(lst, val) :\n
Code \u00e0 trous def recherche_dichotomique(lst, val) :\n indice_debut = ...\n indice_fin = ...\n while ... <= ... :\n ... = (... + ...) // 2 \n ... = lst[...] \n if ... == ... : \n return ...\n if valeur_centrale < ... : \n ... = ... + ...\n else :\n ... = ... - ...\n return None \n
Code \u00e0 trous def recherche_dichotomique(lst, val) :\n indice_debut = ...\n indice_fin = ...\n while ... <= ... :\n indice_centre = (... + ...) // 2 \n ... = lst[...] \n if valeur_centrale == ... : \n return ...\n if valeur_centrale < ... : \n ... = ... + 1\n else :\n ... = ... - 1\n return None \n
Code \u00e0 trous def recherche_dichotomique(lst, val) :\n indice_debut = ...\n indice_fin = ...\n while indice_debut <= ... :\n indice_centre = (... + ...) // 2 \n valeur_centrale = lst[...] \n if valeur_centrale == ... : \n return indice_centre\n if valeur_centrale < ... : \n indice_debut = ... + 1\n else :\n indice_fin = ... - 1\n return None\n
"},{"location":"T4_Algorithmique/4.6_Algorithmes_gloutons/cours/","title":"4.6 Algorithmes gloutons","text":"en anglais : greedy algorithms
D\u00e9finition
Un algorithme est qualifi\u00e9 de glouton si le probl\u00e8me qu'il essaie de r\u00e9soudre est d\u00e9compos\u00e9 en une succession de probl\u00e8mes identiques pour lesquels l'algorithme va chercher une solution optimale.
La question (presque philosophique) est :
Lorsqu'on fait \u00e0 chaque \u00e9tape le meilleur choix possible, est-ce que la solution finale \u00e0 laquelle on arrive est la meilleure possible ?
Formul\u00e9 autrement :
Est-ce que faire le meilleur choix \u00e0 chaque \u00e9tape nous assure le meilleur choix global ?
"},{"location":"T4_Algorithmique/4.6_Algorithmes_gloutons/cours/#1-exemples-dalgorithmes-gloutons","title":"1. Exemples d'algorithmes gloutons","text":""},{"location":"T4_Algorithmique/4.6_Algorithmes_gloutons/cours/#11-un-plus-court-chemin","title":"1.1 Un plus court chemin ?","text":"La philosophie de l'algorithme glouton implique qu'\u00e0 chaque \u00e9tape, vous allez vous diriger vers le point le plus proche.
Quel est alors le parcours final ?
R\u00e9ponseVoil\u00e0 ce que donnerait l'algorithme glouton :
Ce chemin est-il optimal ?
R\u00e9ponseNon ! Celui ci-dessous est meilleur :
Le fait d'avoir privil\u00e9gi\u00e9 \u00e0 chaque \u00e9tape le meilleur choix local nous a emp\u00each\u00e9 de voir le meilleur choix global.
"},{"location":"T4_Algorithmique/4.6_Algorithmes_gloutons/cours/#12-remplir-un-rectangle-avec-des-carres","title":"1.2 Remplir un rectangle avec des carr\u00e9s","text":"(d'apr\u00e8s S.Tummarello et E.Buonocore)
On consid\u00e8re un rectangle de dimension 11 sur 13 (figure 0). On veut remplir ce rectangle avec le minimum de carr\u00e9s.
Un algorithme glouton va chercher \u00e0 positionner d'abord le plus grand carr\u00e9 possible (figure 1).
C'est une strat\u00e9gie efficace (8 carr\u00e9s n\u00e9cessaires), mais qui n'est pas optimale : la figure 2 pr\u00e9sente un pavage avec seulement 6 carr\u00e9s.
Encore une fois, la solution gloutonne n'est pas la solution optimale.
Est-ce qu'un algorithme glouton va toujours passer \u00e0 c\u00f4t\u00e9 de la solution optimale ? Non ! Il arrive aussi qu'il donne la solution optimale. Changeons le rectangle initial en un rectangle de 10 sur 15 :
Dans cette situation, l'algorithme glouton nous am\u00e8ne \u00e0 la solution optimale.
"},{"location":"T4_Algorithmique/4.6_Algorithmes_gloutons/cours/#conclusion","title":"Conclusion","text":"Un algorithme glouton est une m\u00e9thode rapide et souvent efficace, mais qui ne garantit pas l'optimalit\u00e9 de la solution trouv\u00e9e.
La succession de meilleurs choix LOCAUX va nous amener \u00e0 une bonne solution GLOBALE, mais ne nous garantit pas d'arriver \u00e0 la solution optimale.
"},{"location":"T4_Algorithmique/4.6_Algorithmes_gloutons/cours/#2-le-probleme-du-rendu-de-monnaie","title":"2. Le probl\u00e8me du rendu de monnaie","text":"Nous allons travailler avec des pi\u00e8ces (ou billets) de 1, 2, 5, 10, 20, 50, 100, 200 euros.
L'objectif est de cr\u00e9er un programme renvoyant, pour une somme somme_a_rendre
entr\u00e9e en param\u00e8tre, la combinaison utilisant un minimum de pi\u00e8ces ou de billets pour fabriquer la somme somme_a_rendre
.
Par exemple, lorsque vous payez avec 20 \u20ac un objet co\u00fbtant 11 \u20ac, vous pr\u00e9f\u00e9rez qu'on vous rende vos 9 \u20ac de monnaie par \\(9 = 5 + 2 + 2\\) plut\u00f4t que par \\(9=2+2+2+1+1+1\\)
La r\u00e9solution de ce probl\u00e8me peut se faire de mani\u00e8re gloutonne : \u00e0 chaque \u00e9tape, vous allez essayer de rendre la plus grosse pi\u00e8ce (ou billet) possible.
Activit\u00e9 de d\u00e9couverte de l'algorithme
"},{"location":"T4_Algorithmique/4.6_Algorithmes_gloutons/cours/#21-solution-du-probleme","title":"2.1 Solution du probl\u00e8me","text":"Rendu de monnaie
def rendu(somme_a_rendre):\n pieces = [200, 100, 50, 20, 10, 5, 2, 1]\n solution = []\n i = 0 # (1)\n while somme_a_rendre > 0:\n if pieces[i] <= somme_a_rendre : # (2) \n solution.append(pieces[i]) # (3) \n somme_a_rendre = somme_a_rendre - pieces[i] # (4)\n else :\n i += 1 # (5) \n return solution\n
solution
Utilisation : rendu(13)
doit renvoyer [10, 2, 1]
>>> rendu(13)\n [10, 2, 1]\n>>> rendu(58)\n [50, 5, 2, 1]\n
"},{"location":"T4_Algorithmique/4.6_Algorithmes_gloutons/cours/#22-une-solution-optimale","title":"2.2 Une solution optimale ?","text":"Imaginons qu'il n'y ait plus de pi\u00e8ces de 10 et 5 euros. Faites fonctionner votre algorithme pour la somme de 63 euros.
>>> rendu(63)\n [50, 2, 2, 2, 2, 2, 2, 1]\n
Damned ! Mais ce n'est pas une solution optimale ! [20, 20, 20, 2, 1]
serait bien mieux.
Moralit\u00e9 : Lors d'un rendu de monnaie, l'algorithme glouton n'est optimal que sous certaines conditions, ce qui est un peu d\u00e9cevant. Un syst\u00e8me de monnaie qui rend l'algorithme glouton est dit canonique. Il est difficile de caract\u00e9riser math\u00e9matiquement si un syst\u00e8me de monnaie est canonique ou pas.
"},{"location":"T4_Algorithmique/4.6_Algorithmes_gloutons/cours/#3-le-probleme-du-sac-a-dos-knapsack-problem","title":"3. Le probl\u00e8me du sac \u00e0 dos (Knapsack Problem)","text":"Le probl\u00e8me est celui-ci : vous disposez d'un sac d'une contenance limit\u00e9e (sur le dessin ci-dessus, 15kg) dans lequel vous allez mettre des objets qui ont un certain poids et une certaine valeur. Vous souhaitez maximiser la valeur totale des objets que vous mettez dans votre sac. Evidemment, la somme de leur masse ne doit pas d\u00e9passer 15 kg.
Ce probl\u00e8me (de la cat\u00e9gorie des probl\u00e8me dits d'analyse combinatoire) malgr\u00e9 sa simplicit\u00e9 est un probl\u00e8me majeur d'optimisation.
O\u00f9 en est-on de la recherche acad\u00e9mique sur le probl\u00e8me du sac \u00e0 dos ?
Actuellement :
Supposons qu'on dispose d'une liste \u00a0mylist = [[\"A\",3], [\"B\",2], [\"C\",8]]
.
Comment classer les \u00e9l\u00e9ments de cette liste par leur deuxi\u00e8me \u00e9l\u00e9ment ???
Nous allons proc\u00e9der en 2 temps.
"},{"location":"T4_Algorithmique/4.6_Algorithmes_gloutons/cours/#311-une-fonction-qui-renvoie-le-deuxieme-element","title":"3.1.1 Une fonction qui renvoie le deuxi\u00e8me \u00e9l\u00e9ment","text":"Cr\u00e9ons une fonction qui renvoie le deuxi\u00e8me \u00e9l\u00e9ment d'un objet liste
:
def deuxieme(lst) :\n return lst[1]\n
Utilisation :
>>> simpsons = ['Bart', 'Lisa', 'Maggie']\n>>> deuxieme(simpsons)\n 'Lisa'\n
"},{"location":"T4_Algorithmique/4.6_Algorithmes_gloutons/cours/#312-tri-de-la-liste-grace-a-cette-fonction-deuxieme","title":"3.1.2 Tri de la liste gr\u00e2ce \u00e0 cette fonction deuxieme
","text":"Nous allons utiliser la fonction sorted
, qui prend en param\u00e8tre une liste \u00e0 trier et une fonction de tri.
>>> mylist = [[\"A\", 3], [\"B\", 2], [\"C\", 8]]\n>>> mynewlist = sorted(mylist, key = deuxieme, reverse = True)\n>>> mynewlist\n[['C', 8], ['A', 3], ['B', 2]]\n
Cette m\u00e9thode de tri va nous \u00eatre tr\u00e8s utile.
"},{"location":"T4_Algorithmique/4.6_Algorithmes_gloutons/cours/#32-retour-sur-le-probleme-du-sac-a-dos","title":"3.2 Retour sur le probl\u00e8me du sac \u00e0 dos","text":"On consid\u00e8re un sac de 40 kg et les objets suivants :
objet A B C D E F masse (en kg) 13 12 8 10 14 18 valeur (en \u20ac) 700 500 200 300 600 800Quels objets faut-il prendre ?
Strat\u00e9gie gloutonne :
On consid\u00e8re la liste
objets = [[\"A\", 13, 700], [\"B\", 12, 500], [\"C\", 8, 200], [\"D\", 10, 300], [\"E\", 14, 600], [\"F\", 18, 800]]\n
En s'inspirant du 3.1.2, on classe ces objets suivant leur taux de valeur.
\u00e0 vous
objets = [[\"A\", 13, 700], [\"B\", 12, 500], [\"C\", 8, 200], [\"D\", 10, 300], [\"E\", 14, 600], [\"F\", 18, 800]]\n\ndef ratio(objet):\n # renvoie le rapport prix/poids d'un objet\n return objet[2] / objet[1]\n\nobjets_tries = sorted(objets, key = ratio, reverse = True)\n
>>> objets_tries\n [['A', 13, 700],\n ['F', 18, 800],\n ['E', 14, 600],\n ['B', 12, 500],\n ['D', 10, 300],\n ['C', 8, 200]]\n
"},{"location":"T4_Algorithmique/4.6_Algorithmes_gloutons/cours/#322-calcul-de-la-solution-par-methode-gloutonne","title":"3.2.2 Calcul de la solution, par m\u00e9thode gloutonne","text":"\u00e0 vous
objets = [[\"A\", 13, 700], [\"B\", 12, 500], [\"C\", 8, 200], [\"D\", 10, 300], [\"E\", 14, 600], [\"F\", 18, 800]]\n\ndef ratio(objet):\n # renvoie le rapport prix/poids d'un objet\n return objet[2] / objet[1]\n\nobjets_tries = sorted(objets, key = ratio, reverse = True)\n\npoids_max = 40\npoids_sac = 0\n\nbutin = []\n\nfor objet in objets_tries:\n poids_objet = objet[1]\n if poids_objet + poids_sac <= poids_max :\n butin.append(objet[0])\n poids_sac += poids_objet\n
>>> butin\n ['A', 'F', 'C']\n
Il faut donc choisir la combinaison A, F, C. Elle est bien valide (poids 39) et rapporte 1700.
Question (toujours la m\u00eame) :
L'algorithme glouton nous a-t-il donn\u00e9 la solution optimale ? Nous allons pour cela avoir recours \u00e0 la force brute pour tester toutes les combinaisons possibles.
"},{"location":"T4_Algorithmique/4.6_Algorithmes_gloutons/cours/#33-force-brute","title":"3.3 Force brute","text":"objets = [[\"A\", 13, 700], [\"B\", 12, 500], [\"C\", 8, 200], [\"D\", 10, 300], [\"E\", 14, 600], [\"F\", 18, 800]]\npoids_max = 40\n
"},{"location":"T4_Algorithmique/4.6_Algorithmes_gloutons/cours/#331-la-liste-de-tous-les-mots-possibles","title":"3.3.1 La liste de tous les mots possibles","text":"combinaisons = []\nfor i in range(2**len(objets)):\n k = bin(i)[2:]\n s = '0'*(len(objets)-len(k)) + k\n combinaisons.append(s)\n
La liste combinaisons
contient bien les 64 mots possibles (\\(2^6=64\\)) :
>>> combinaisons\n ['000000',\n '000001',\n '000010',\n '000011',\n '000100',\n '000101',\n '000110',\n '000111',\n '001000',\n '001001',\n '001010',\n '001011',\n '001100',\n '001101',\n '001110',\n '001111',\n '010000',\n '010001',\n '010010',\n '010011',\n '010100',\n '010101',\n '010110',\n '010111',\n '011000',\n '011001',\n '011010',\n '011011',\n '011100',\n '011101',\n '011110',\n '011111',\n '100000',\n '100001',\n '100010',\n '100011',\n '100100',\n '100101',\n '100110',\n '100111',\n '101000',\n '101001',\n '101010',\n '101011',\n '101100',\n '101101',\n '101110',\n '101111',\n '110000',\n '110001',\n '110010',\n '110011',\n '110100',\n '110101',\n '110110',\n '110111',\n '111000',\n '111001',\n '111010',\n '111011',\n '111100',\n '111101',\n '111110',\n '111111']\n
valeurs = [] \npoids = []\nfor comb in combinaisons :\n poids_comb = 0\n valeur = 0\n for i in range(len(objets)): \n if comb[i] == '1':\n poids_comb += objets[i][1]\n valeur += objets[i][2]\n if poids_comb > poids_max :\n valeur = 0\n valeurs.append(valeur)\n poids.append(poids_comb)\n\nvaleur_max = max(valeurs)\nmeilleure_comb = combinaisons[valeurs.index(valeur_max)]\npoids_comb = poids[valeurs.index(valeur_max)]\n\nmot_sol = \"\"\nfor k in range(len(meilleure_comb)) :\n if meilleure_comb[k] == '1' :\n mot_sol += objets[k][0]\n
>>> mot_sol\n 'ABE'\n
re-Damned ! La force brute a mis en \u00e9vidence une combinaison meilleure que celle donn\u00e9e par l'algorithme glouton.
En effet la combinaison A-B-E est bien valide (poids total 39) et rapporte 1800, donc 100 de mieux que la solution gloutonne.
Par contre, la force brute est inenvisageable pour si le nombre d'objets est grand, alors que la strat\u00e9gie gloutonne reste tr\u00e8s rapide.
"},{"location":"T4_Algorithmique/4.6_Algorithmes_gloutons/cours/#conclusion_1","title":"Conclusion","text":"La strat\u00e9gie gloutonne donne tr\u00e8s rapidement des solutions satisfaisantes mais pas forc\u00e9ment optimales. Pour beaucoup de probl\u00e8mes (dont le probl\u00e8me du sac \u00e0 dos), la recherche d'une solution optimale sans passer par la force brute semble impossible (mais n'est pas d\u00e9montr\u00e9e). Dans ce cas-l\u00e0, la strat\u00e9gie gloutonne peut \u00eatre employ\u00e9e pour avoir vite et bien une solution convenable, m\u00eame si peut-\u00eatre non optimale. On dit que la strat\u00e9gie gloutonne est une heuristique de r\u00e9solution. On sait que ce n'est pas forc\u00e9ment optimal, mais faute de mieux, on s'en contente...
"},{"location":"T4_Algorithmique/4.6_Algorithmes_gloutons/intro_rendu/","title":"Vers l'algorithme de rendu de monnaie","text":"On veut coder la fonction rendu
qui prend pour param\u00e8tre un entier positif somme_a_rendre
et qui renvoie la liste des pi\u00e8ces \u00e0 donner.
Les pieces disponibles (en quantit\u00e9 illimit\u00e9e) sont stock\u00e9es dans une variable pieces = [200, 100, 50, 20, 10, 5, 2, 1]
.
Utilisation : rendu(13)
doit renvoyer [10, 2, 1]
>>> rendu(13)\n [10, 2, 1]\n>>> rendu(58)\n [50, 5, 2, 1]\n
Code \u00e0 trous def rendu(somme_a_rendre):\n pieces = [200, 100, 50, 20, 10, 5, 2, 1]\n solution = []\n ...\n ...\n ...\n ...\n ...\n ...\n ... \n return solution \n
Code \u00e0 trous def rendu(somme_a_rendre):\n pieces = [200, 100, 50, 20, 10, 5, 2, 1]\n solution = []\n i = ... \n while ... > ...:\n if ... <= ... : \n ....append(...) \n ... = ... - ... \n else :\n ... += ... \n return solution \n
Code \u00e0 trous def rendu(somme_a_rendre):\n pieces = [200, 100, 50, 20, 10, 5, 2, 1]\n solution = []\n i = 0 \n while ... > ...:\n if pieces[i] <= ... : \n solution.append(...) \n somme_a_rendre = ... - ... \n else :\n ... += ... \n return solution \n
Code \u00e0 trous def rendu(somme_a_rendre):\n pieces = [200, 100, 50, 20, 10, 5, 2, 1]\n solution = []\n i = 0 \n while somme_a_rendre > ...:\n if pieces[i] <= somme_a_rendre : \n solution.append(...) \n somme_a_rendre = ... - ... \n else :\n i += 1 \n return solution\n
"},{"location":"T4_Algorithmique/4.7_Algorithme_KNN/07_Algorithme_KNN/","title":"M\u00e9thode du K-Nearest-Neighbours (KNN), aka les k-plus-proches-voisins","text":"La m\u00e9thode KNN est une m\u00e9thode simple et efficace de classification. La classification est un enjeu majeur de l'Intelligence Artificielle : - la cam\u00e9ra d'une voiture autonome per\u00e7oit un panneau, mais quel est ce panneau ? - un grain de beaut\u00e9 est pris en photo par un dermatologue, ce grain de beaut\u00e9 est-il canc\u00e9reux ? - ...
La m\u00e9thode du KNN va trouver quels sont, dans une base de donn\u00e9es d\u00e9j\u00e0 bien remplie et labell\u00e9e, les k-objets (les 6 objets si \\(k=6\\) par exemple) qui se rapprochent le plus de l'objet \u00e0 classifier. En prenant ensuite la caract\u00e9ristique la plus fr\u00e9quente parmi ces 6 objets, on devine alors dans quelle cat\u00e9gorie notre objet doit se classer.
Notre objectif : Nous allons reprendre le jeu de donn\u00e9es sur les joueurs du top14 utilis\u00e9 ici dans le cours \u00abTrier des donn\u00e9es\u00bb
Question : si on croise une personne nous disant qu'elle veut jouer en top14, et qu'elle nous donne son poids et sa taille, peut-on lui pr\u00e9dire \u00e0 quel poste elle devrait jouer ?
Dans toute id\u00e9e de classification il y a l'id\u00e9e de distance. Il faut comprendre la distance comme une mesure de la diff\u00e9rence.
Comment mesurer la diff\u00e9rence physique entre deux joueurs de rugby ?
import pandas as pd #import du module pandas, abr\u00e9g\u00e9 classiquement par \"pd\"\n
df = pd.read_csv('data/top14.csv', encoding = 'utf-8')\n
"},{"location":"T4_Algorithmique/4.7_Algorithme_KNN/07_Algorithme_KNN/#resultat-attendu","title":"R\u00e9sultat attendu :","text":"Il faut cr\u00e9er une fonction knn()
qui prend en argument poids
et taille
, sont les caract\u00e9ristiques du nouveau joueur. La fonction doit renvoyer une cha\u00eene de caract\u00e8re correspondant au poste auquel elle est susceptible de jouer.
Exemple :
def knn(poids, taille):\n df['distance']=(df['Taille']-taille)**2+(df['Poids']-poids)**2\n newdf = df.sort_values(by='distance', ascending=True)\n newdftri = newdf.head(6) #on prend les 6 joueurs les plus proches physiquement\n sol = newdftri['Poste'].describe().top\n return sol\n
knn(93,188)\n
'Ailier'\n
"},{"location":"T4_Algorithmique/4.7_Algorithme_KNN/07_Algorithme_KNN/#influence-du-parametre-k","title":"Influence du param\u00e8tre \\(k\\)","text":"Dans le code pr\u00e9c\u00e9dent, on a travaill\u00e9 avec \\(k=6\\) et c'est le poste majoritaire parmi les 6 joueurs les plus proches qui a \u00e9t\u00e9 donn\u00e9 par l'algorithme. Modifions l\u00e9g\u00e8rement la fonction knn()
afin d'observer l'influence du param\u00e8tre \\(k\\) sur la pr\u00e9diction :
def knn(poids, taille, k):\n df['distance']=(df['Taille']-taille)**2+(df['Poids']-poids)**2\n newdf = df.sort_values(by='distance', ascending=True)\n newdftri = newdf.head(k) #on prend les k joueurs les plus proches physiquement\n sol = newdftri['Poste'].describe().top\n return sol\n\nfor k in range(1,20):\n print(knn(93,188,k))\n
Centre\nAilier\nAilier\nAilier\nAilier\nAilier\nAilier\nAilier\nAilier\nAilier\nAilier\nAilier\nAilier\nAilier\nAilier\nAilier\nAilier\nAilier\nAilier\n
On s'aper\u00e7oit que la pr\u00e9diction est tr\u00e8s stable... sauf si \\(k=1\\) ! Il se trouve qu'un joueur poss\u00e8de exactement ces caract\u00e9ristiques physiques (Pierre-Louis BARASSI) et qu'il joue Centre :
df['distance']=(df['Taille']-188)**2+(df['Poids']-93)**2\nnewdf = df.sort_values(by='distance', ascending=True)\nnewdf.head(10)\n
Equipe Nom Poste Date de naissance Taille Poids distance 314 Lyon Pierre-Louis BARASSI Centre 22/04/1998 188 93 0 461 Pau Vincent PINTO Ailier 10/04/1999 187 93 1 527 Toulon St\u00e9phane ONAMB\u00c9L\u00c9 3\u00e8me ligne 12/02/1993 188 94 1 202 Castres Geoffrey PALIS Arri\u00e8re 08/07/1991 189 93 1 196 Castres Armand BATLLE Ailier 12/04/1987 188 92 1 585 Toulouse Th\u00e9o BELAN Centre 15/11/1992 187 94 2 242 Clermont Samuel EZEALA Ailier 11/12/1999 187 94 2 502 Racing92 Simon ZEBO Ailier 16/03/1990 187 94 2 133 Brive Esteban ABADIE 3\u00e8me ligne 01/12/1997 188 95 4 369 Montpellier Benjamin FALL Arri\u00e8re 03/03/1989 186 93 4 On peut s'apercevoir aussi que jusqu'\u00e0 \\(k=5\\), aucun poste n'est majoritaire : la pr\u00e9diction pourrait aussi bien renvoyer Centre, 3\u00e8me ligne, ou Arri\u00e8re. Ce n'est que gr\u00e2ce \u00e0 l'ordre alphab\u00e9tique que la r\u00e9ponse renvoy\u00e9e est \u00abAilier\u00bb. Par contre, d\u00e8s que \\(k \\geqslant 5\\), le poste d'Ailier est bien majoritaire parmi les \\(k\\) plus proches voisins.
\n
"},{"location":"T4_Algorithmique/4.7_Algorithme_KNN/cours/","title":"4.7 Algorithme des KNN","text":"Algorithme des K-Nearest-Neighbours (KNN), aka les k-plus-proches-voisins
La m\u00e9thode KNN est une m\u00e9thode simple et efficace de classification. La classification est un enjeu majeur de l'Intelligence Artificielle :
La m\u00e9thode du KNN va trouver quels sont, dans une base de donn\u00e9es d\u00e9j\u00e0 bien remplie et labell\u00e9e, les k-objets (les 6 objets si \\(k=6\\) par exemple) qui se rapprochent le plus de l'objet \u00e0 classifier. En prenant ensuite la caract\u00e9ristique la plus fr\u00e9quente parmi ces 6 objets, on devine alors dans quelle cat\u00e9gorie notre objet doit se classer.
"},{"location":"T4_Algorithmique/4.7_Algorithme_KNN/cours/#1-objectif","title":"1. Objectif","text":"Nous allons reprendre le jeu de donn\u00e9es sur les joueurs du Top14 utilis\u00e9 dans le cours \u00abTrier des donn\u00e9es\u00bb
Nous souhaitons pouvoir r\u00e9pondre \u00e0 cette question :
Question
Si on croise une personne (qu'on appelera joueur X) nous disant qu'elle veut jouer en Top14, et qu'elle nous donne son poids et sa taille, peut-on lui pr\u00e9dire \u00e0 quel poste elle devrait jouer ?
Nous devons donc cr\u00e9er une fonction conseil_poste
qui prend en argument poids
et taille
, qui sont les caract\u00e9ristiques du joueur X. Cette fonction prendra aussi en param\u00e8tre un nombre k
qui sera le nombre de voisins utilis\u00e9s pour d\u00e9terminer le poste conseill\u00e9.
La fonction doit renvoyer une cha\u00eene de caract\u00e8re correspondant au poste auquel on lui conseille de jouer.
Il va falloir pour cela classer tous les joueurs du Top14 suivant leur proximit\u00e9 morphologique avec notre joueur X, et prendre parmi les k
premiers joueurs le poste majoritaire.
distance
morphologique","text":"Dans toute id\u00e9e de classification il y a l'id\u00e9e de distance. Il faut comprendre la distance comme une mesure de la diff\u00e9rence.
Comment mesurer la diff\u00e9rence physique entre deux joueurs de rugby ?
Fonction distance
\u00c9crire une fonction distance
qui re\u00e7oit en param\u00e8tres :
poids
: le poids du joueur Xtaille
: la taille du joueur Xplayer
: un joueur de la liste joueurs
et qui renvoie la distance morphologique du joueur X avec player
.
Exemple d'utilisation :
>>> distance(93, 190, joueurs[34])\n445\n
Correction def distance(poids, taille, player):\n p = int(player['Poids'])\n t = int(player['Taille'])\n return (poids-p)**2 + (taille-t)**2\n
"},{"location":"T4_Algorithmique/4.7_Algorithme_KNN/cours/#3-classement-des-joueurs-suivant-leur-proximite-morphologique","title":"3. Classement des joueurs suivant leur proximit\u00e9 morphologique","text":"De la m\u00eame mani\u00e8re qu'on avait class\u00e9 les joueurs suivant leur IMC, on peut les classer suivant leur proximit\u00e9 morphologique avec le joueur X.
"},{"location":"T4_Algorithmique/4.7_Algorithme_KNN/cours/#31-fonction-second","title":"3.1 Fonctionsecond
","text":"Fonction second
\u00c9crire une fonction second
qui re\u00e7oit en param\u00e8tres :
couple
: un couple de valeurset qui renvoie le deuxi\u00e8me \u00e9l\u00e9ment du couple.
Exemple d'utilisation :
>>> cpl = (\"vendredi\", 13)\n>>> second(cpl)\n13\n
Correction def second(cpl):\n return cpl[1]\n
"},{"location":"T4_Algorithmique/4.7_Algorithme_KNN/cours/#32-classement-des-k-plus-proches-joueurs","title":"3.2 Classement des k plus proches joueurs","text":"Fonction classement_k_joueurs
\u00c9crire une fonction classement_k_joueurs
qui re\u00e7oit en param\u00e8tres :
poids
: le poids du joueur Xtaille
: la taille du joueur Xk
: le nombre de joueurs les plus proches que l'on veut garderet qui renvoie une liste contenant les k joueurs class\u00e9s suivant leur proximit\u00e9 morphologique avec le joueur X.
Exemple d'utilisation :
>>> classement_k_joueurs(85, 186, 3)\n[{'Equipe': 'Bordeaux', 'Nom': 'Geoffrey CROS', 'Poste': 'Arri\u00e8re', 'Date de naissance': '08/03/1997', 'Taille': '185', 'Poids': '85'}, {'Equipe': 'Toulouse', 'Nom': 'Romain NTAMACK', 'Poste': 'Ouverture', 'Date de naissance': '01/05/1999', 'Taille': '186', 'Poids': '84'}, {'Equipe': 'Bayonne', 'Nom': 'Manuel ORDAS', 'Poste': 'Ouverture', 'Date de naissance': '21/02/1998', 'Taille': '186', 'Poids': '83'}]\n
Correction def classement_k_joueurs(poids, taille):\n couples = []\n for player in joueurs:\n couples.append((player, distance(poids, taille, player)))\n couples_tries = sorted(couples, key=second)\n joueurs_classes = [couple[0] for couple in couples_tries]\n return joueurs_classes[:k]\n
"},{"location":"T4_Algorithmique/4.7_Algorithme_KNN/cours/#4-recherche-du-poste-le-plus-represente","title":"4. Recherche du poste le plus repr\u00e9sent\u00e9","text":""},{"location":"T4_Algorithmique/4.7_Algorithme_KNN/cours/#41-dictionnaire-doccurence-des-postes","title":"4.1 Dictionnaire d'occurence des postes","text":"Fonction occurence
\u00c9crire une fonction occurence
qui re\u00e7oit en param\u00e8tres :
joueurs
: une liste de joueurset qui renvoie le dictionnaire compos\u00e9 diff\u00e9rents postes de ces joueurs, et du nombre de fois o\u00f9 ils apparaissent dans la liste joueurs
.
Exemple d'utilisation :
>>> occurence(joueurs)\n{'Pilier': 110, 'Talonneur': 50, '2\u00e8me ligne': 74, '3\u00e8me ligne': 111, 'M\u00eal\u00e9e': 42, 'Ouverture': 38, 'Centre': 71, 'Ailier': 64, 'Arri\u00e8re': 35}\n
Correction def occurence(joueurs):\n occ = {}\n for player in joueurs:\n if player['Poste'] in occ:\n occ[player['Poste']] += 1\n else:\n occ[player['Poste']] = 1\n return occ\n
"},{"location":"T4_Algorithmique/4.7_Algorithme_KNN/cours/#42-tri-dun-dictionnaire","title":"4.2 Tri d'un dictionnaire","text":"Fonction cle_max
\u00c9crire une fonction cle_max
qui re\u00e7oit en param\u00e8tre :
d
: un dictionnaire dont les cl\u00e9s sont des chaines de caract\u00e8re et les valeurs sont des nombres.et qui renvoie la cl\u00e9 associ\u00e9e \u00e0 la valeur maximale.
Exemple d'utilisation :
>>> d = {\"lundi\":13, \"mardi\":9, \"mercredi\":18, \"jeudi\":4}\n>>> cle_max(d)\n'mercredi'\n
Correction def cle_max(d):\n maxi = 0\n for key in d:\n if d[key] > maxi:\n maxi = d[key]\n key_max = key\n return key_max\n
"},{"location":"T4_Algorithmique/4.7_Algorithme_KNN/cours/#43-fonction-conseil_poste","title":"4.3 Fonction conseil_poste
","text":"Fonction conseil_poste
\u00c9crire une fonction conseil_poste
qui re\u00e7oit en param\u00e8tres :
poids
: le poids du joueur Xtaille
: la taille du joueur Xk
: le nombre de joueurs les plus proches sur lequel on se base pour faire la pr\u00e9dictionet qui renvoie le poste le plus compatible avec la morphologie de X.
Exemple d'utilisation :
>>> conseil_poste(70, 170, 6)\n'M\u00eal\u00e9e'\n>>> conseil_poste(120, 210, 6)\n'2\u00e8me ligne'\n
Correction def conseil_poste(poids, taille, k):\n joueurs_classes = classement_k_joueurs(poids, taille, k)\n dico = occurence(joueurs_classes)\n poste_conseille = cle_max(dico)\n return poste_conseille\n
Faire varier les diff\u00e9rents param\u00e8tres pour observer leur r\u00f4le respectif.
"},{"location":"T5_Traitement_de_donnees/sommaire/","title":"Th\u00e8me 5 : Traitement de donn\u00e9es","text":"Les fichiers CSV (pour Comma Separated Values) sont des fichiers-texte (ils ne contiennent aucune mise en forme) utilis\u00e9s pour stocker des donn\u00e9es, s\u00e9par\u00e9es par des virgules (ou des points-virgules, ou des espaces...). Il n'y a pas de norme officielle du CSV.
"},{"location":"T5_Traitement_de_donnees/5.1_Manipulation_csv/cours/#1-ouverture-dun-fichier-csv-par-des-logiciels-classiques","title":"1. Ouverture d'un fichier CSV par des logiciels classiques","text":"L'utilisation d'un tableur peut \u00eatre d\u00e9licate lorsque le fichier CSV comporte un tr\u00e8s grand nombre de lignes. Python permet de lire et d'extraire des informations d'un fichier CSV m\u00eame tr\u00e8s volumineux, gr\u00e2ce \u00e0 des modules d\u00e9di\u00e9s, comme le bien-nomm\u00e9 csv
(utilis\u00e9 ici) ou bien pandas
(qui sera vu plus tard).
Le script suivant :
import csv \nf = open('exemple.csv', \"r\", encoding = 'utf-8') # le \"r\" signifie \"read\", le fichier est ouvert en lecture seule\ndonnees = csv.reader(f) # donnees est un objet (sp\u00e9cifique au module csv) qui contient des lignes\n\nfor ligne in donnees: \n print(ligne)\n\nf.close() # toujours fermer le fichier !\n
donne :
['Pr\u00e9nom', 'Nom', 'Email', 'SMS']\n['John', 'Smith', 'john@example.com', '33123456789']\n['Harry', 'Pierce', 'harry@example.com', '33111222222']\n['Howard', 'Paige', 'howard@example.com', '33777888898']\n
Probl\u00e8mes
donnees
n'est pas exploitable en l'\u00e9tat. Ce n'est pas une structure connue.Au lieu d'utiliser la fonction csv.reader()
, utilisons csv.DictReader()
. Comme son nom l'indique, elle renverra une variable contenant des dictionnaires.
Le script suivant :
import csv\nf = open('exemple.csv', \"r\", encoding = 'utf-8')\ndonnees = csv.DictReader(f)\n\nfor ligne in donnees:\n print(dict(ligne))\n\nf.close()\n
donne
{'Pr\u00e9nom': 'John', 'Nom': 'Smith', 'Email': 'john@example.com', 'SMS': '33123456789'}\n{'Pr\u00e9nom': 'Harry', 'Nom': 'Pierce', 'Email': 'harry@example.com', 'SMS': '33111222222'}\n{'Pr\u00e9nom': 'Howard', 'Nom': 'Paige', 'Email': 'howard@example.com', 'SMS': '33777888898'}\n
C'est mieux ! Les donn\u00e9es sont maintenant des dictionnaires. Mais nous avons juste \u00e9num\u00e9r\u00e9 3 dictionnaires. Comment r\u00e9-acc\u00e9der au premier d'entre eux, celui de John Smith ? Essayons :
>>> donnees[0]\n\n ---------------------------------------------------------------------------\n\n TypeError Traceback (most recent call last)\n\n <ipython-input-3-9914ab00321e> in <module>\n ----> 1 donnees[0]\n\n\n TypeError: 'DictReader' object does not support indexing\n
"},{"location":"T5_Traitement_de_donnees/5.1_Manipulation_csv/cours/#23-une-liste-de-dictionnaires","title":"2.3 Une liste de dictionnaires","text":"Nous allons donc cr\u00e9er une liste de dictionnaires.
Le script suivant :
import csv\nf = open('exemple.csv', \"r\", encoding = 'utf-8')\ndonnees = csv.DictReader(f)\namis = []\nfor ligne in donnees:\n amis.append(dict(ligne))\n\nf.close()\n
permet de faire ceci :
>>> amis\n\n [{'Pr\u00e9nom': 'John',\n 'Nom': 'Smith',\n 'Email': 'john@example.com',\n 'SMS': '33123456789'},\n {'Pr\u00e9nom': 'Harry',\n 'Nom': 'Pierce',\n 'Email': 'harry@example.com',\n 'SMS': '33111222222'},\n {'Pr\u00e9nom': 'Howard',\n 'Nom': 'Paige',\n 'Email': 'howard@example.com',\n 'SMS': '33777888898'}]\n\n>>> print(amis[0]['Email'])\n john@example.com\n\n>>> print(amis[2]['Nom'])\n Paige\n
"},{"location":"T5_Traitement_de_donnees/5.1_Manipulation_csv/cours/#3-un-fichier-un-peu-plus-interessant-les-joueurs-de-rugby-du-top14","title":"3. Un fichier un peu plus int\u00e9ressant : les joueurs de rugby du TOP14","text":"Le fichier top14.csv
contient tous les joueurs du Top14 de rugby, saison 2019-2020, avec leur date de naissance, leur poste, et leurs mensurations.
Ce fichier a \u00e9t\u00e9 g\u00e9n\u00e9r\u00e9 par R\u00e9mi Deniaud, de l'acad\u00e9mie de Bordeaux.
Q1. Stocker dans une variable joueurs
les renseignements de tous les joueurs pr\u00e9sents dans ce fichier csv.
import csv\nf = open('data/top14.csv', \"r\", encoding = 'utf-8')\ndonnees = csv.DictReader(f)\njoueurs = []\nfor ligne in donnees:\n joueurs.append(dict(ligne))\n\nf.close()\n
"},{"location":"T5_Traitement_de_donnees/5.1_Manipulation_csv/cours/#31-premiere-analyse","title":"3.1 Premi\u00e8re analyse","text":"Q2. Combien de joueurs sont pr\u00e9sents dans ce fichier ?
r\u00e9ponse```python
len(joueurs) 595 ```}
Q3. Quel est le nom du joueur n\u00b0486 ?
r\u00e9ponse>>> joueurs[486]['Nom']\n 'Wenceslas LAURET'\n
"},{"location":"T5_Traitement_de_donnees/5.1_Manipulation_csv/cours/#32-extraction-de-donnees-particulieres","title":"3.2 Extraction de donn\u00e9es particuli\u00e8res","text":"Q4. O\u00f9 joue Baptiste SERIN ?
La m\u00e9thode la plus naturelle est de parcourir toute la liste jusqu'\u00e0 trouver le bon joueur, puis d'afficher son \u00e9quipe.
r\u00e9ponse>>> for joueur in joueurs :\n if joueur['Nom'] == 'Baptiste SERIN' :\n print(joueur['Equipe'])\n
Une m\u00e9thode plus efficace est d'utiliser une liste par compr\u00e9hension incluant un test.
r\u00e9ponse>>> clubSerin = [joueur['Equipe'] for joueur in joueurs if joueur['Nom'] == 'Baptiste SERIN']\n>>> clubSerin\n
Q5. Qui sont les joueurs de plus de 140 kg ?
Attention \u00e0 bien convertir en entier la chaine de caract\u00e8re renvoy\u00e9e par la cl\u00e9 Poids
, \u00e0 l'aide de la fonction int()
.
>>> lourds = [(joueur['Nom'], joueur['Poids']) for joueur in joueurs if int(joueur['Poids']) > 140]\n>>> lourds\n
"},{"location":"T5_Traitement_de_donnees/5.1_Manipulation_csv/cours/#4-exploitation-graphique","title":"4. Exploitation graphique","text":"Nous allons utiliser le module Matplotlib pour illustrer les donn\u00e9es de notre fichier csv.
"},{"location":"T5_Traitement_de_donnees/5.1_Manipulation_csv/cours/#41-exemple","title":"4.1 Exemple","text":"import matplotlib.pyplot as plt\nX = [0,1,3,6]\nY = [12,10,7,15]\nplt.plot(X,Y,'ro') # r pour red, o pour un cercle. voir https://matplotlib.org/api/markers_api.html\nplt.show()\n
"},{"location":"T5_Traitement_de_donnees/5.1_Manipulation_csv/cours/#42-application","title":"4.2 Application","text":"Q1. Afficher sur un graphique tous les joueurs de rugby du Top14, en mettant le poids en abscisse et la taille en ordonn\u00e9e.
r\u00e9ponseX = [int(joueur['Poids']) for joueur in joueurs]\nY = [int(joueur['Taille']) for joueur in joueurs]\nplt.plot(X, Y, 'ro') # r pour red, o pour un cercle. voir https://matplotlib.org/api/markers_api.html\nplt.show()\n
Q2. Faire appara\u00eetre ensuite les joueurs \u00e9voluant au poste de Centre en bleu, et les 2\u00e8me lignes en vert.
r\u00e9ponse#tous les joueurs\nX = [int(joueur['Poids']) for joueur in joueurs]\nY = [int(joueur['Taille']) for joueur in joueurs]\nplt.plot(X, Y, 'ro') \n\n#on recolorie les Centres en bleu\nX = [int(joueur['Poids']) for joueur in joueurs if joueur['Poste'] == 'Centre']\nY = [int(joueur['Taille']) for joueur in joueurs if joueur['Poste'] == 'Centre']\nplt.plot(X, Y, 'bo')\n\n#on recolorie les 2\u00e8me ligne en vert\nX = [int(joueur['Poids']) for joueur in joueurs if joueur['Poste'] == '2\u00e8me ligne']\nY = [int(joueur['Taille']) for joueur in joueurs if joueur['Poste'] == '2\u00e8me ligne']\nplt.plot(X, Y, 'go')\n\n\nplt.show()\n
"},{"location":"T5_Traitement_de_donnees/5.2_Trier_des_donnees/cours/","title":"5.2 Trier des donn\u00e9es","text":"Nous reprenons notre fichier de joueurs de rugby du Top14. : top14.csv
import csv\nf = open('top14.csv', \"r\", encoding = 'utf-8')\ndonnees = csv.DictReader(f)\njoueurs = []\nfor ligne in donnees:\n joueurs.append(dict(ligne))\n\nf.close()\n
"},{"location":"T5_Traitement_de_donnees/5.2_Trier_des_donnees/cours/#1-creer-une-fonction-filtre","title":"1. Cr\u00e9er une fonction filtre","text":"L'objectif est de cr\u00e9er une fonction joueursEquipe(equipe)
qui renvoie une liste contentant tous les joueurs de l'\u00e9quipe equipe
. Le param\u00e8tre equipe
sera donn\u00e9e sous forme de cha\u00eene de caract\u00e8res. La valeur renvoy\u00e9e sera de type liste.
Utilisation :
>>> joueursEquipe('Bordeaux')\n[{'Equipe': 'Bordeaux', 'Nom': 'Jefferson POIROT', 'Poste': 'Pilier', 'Date de naissance': '01/11/1992', 'Taille': '181', 'Poids': '117'}, {'Equipe': 'Bordeaux', 'Nom': 'Lasha TABIDZE', 'Poste': 'Pilier', 'Date de naissance': '04/07/1997', 'Taille': '185', 'Poids': '117'}, {'Equipe': 'Bordeaux', 'Nom': 'Laurent DEL.....\n
r\u00e9ponse def joueursEquipe(equipe): \n return [player for player in joueurs if player[\"Equipe\"] == equipe]\n
D\u00e9finir de la m\u00eame mani\u00e8re une fonction joueursPoste(poste)
.
Utilisation :
>>> joueursPoste(\"Talonneur\")\n[{'Equipe': 'Agen', 'Nom': 'Cl\u00e9ment MARTINEZ', 'Poste': 'Talonneur', 'Date de naissance': '14/03/1996', 'Taille': '181', 'Poids': '105'}, {'Equipe': 'Agen', 'Nom': 'Marc BARTHOMEUF', 'Poste': 'T...\n
r\u00e9ponse def joueursPoste(poste): \n return [player for player in joueurs if player[\"Poste\"] == poste]\n
"},{"location":"T5_Traitement_de_donnees/5.2_Trier_des_donnees/cours/#2-utilisation-dune-fonction-de-tri","title":"2. Utilisation d'une fonction de tri","text":""},{"location":"T5_Traitement_de_donnees/5.2_Trier_des_donnees/cours/#21-le-probleme","title":"2.1 Le probl\u00e8me","text":"Comment classer les joueurs suivant leur taille ? La fonction sorted(liste)
est efficace sur les listes : elle renvoie une nouvelle liste tri\u00e9e dans l'ordre croissant.
>>> mylist = [4,2,8,6]\n>>> mynewlist = sorted(mylist)\n>>> print(mynewlist)\n [2, 4, 6, 8]\n
Mais comment trier un dictionnaire ?
>>> test = sorted(joueurs)\n
---------------------------------------------------------------------------\n\nTypeError Traceback (most recent call last)\n\n<ipython-input-14-de081d14a3da> in <module>\n----> 1 test = sorted(joueurs)\n\n\nTypeError: '<' not supported between instances of 'dict' and 'dict'\n
Il est normal que cette tentative \u00e9choue : un dictionnaire poss\u00e8de plusieurs cl\u00e9s diff\u00e9rentes. Ici, plusieurs cl\u00e9s peuvent \u00eatre des crit\u00e8res de tri : la taille, le poids.
"},{"location":"T5_Traitement_de_donnees/5.2_Trier_des_donnees/cours/#22-un-exemple-de-tri-de-dictionnaire","title":"2.2 Un exemple de tri de dictionnaire","text":">>> Simpsons = [{\"Prenom\" : \"Bart\", \"age estim\u00e9\": \"10\"},\n {\"Prenom\" : \"Lisa\", \"age estim\u00e9\": \"8\"},\n {\"Prenom\" : \"Maggie\", \"age estim\u00e9\": \"1\"},\n {\"Prenom\" : \"Homer\", \"age estim\u00e9\": \"38\"},\n {\"Prenom\" : \"Marge\", \"age estim\u00e9\": \"37\"}]\n
>>> def age(personnage):\n return int(personnage[\"age estim\u00e9\"])\n
>>> age(Simpsons[0])\n 10\n
La cr\u00e9ation de cette fonction age()
va nous permettre de sp\u00e9cifier une cl\u00e9 de tri, par le param\u00e8tre key
:
Tri d'un dictionnaire
>>> triSimpsons = sorted(Simpsons, key = age)\n
>>> triSimpsons\n [{'Prenom': 'Maggie', 'age estim\u00e9': '1'},\n {'Prenom': 'Lisa', 'age estim\u00e9': '8'},\n {'Prenom': 'Bart', 'age estim\u00e9': '10'},\n {'Prenom': 'Marge', 'age estim\u00e9': '37'},\n {'Prenom': 'Homer', 'age estim\u00e9': '38'}]\n
On peut aussi inverser l'ordre de tri :
>>> triSimpsons = sorted(Simpsons, key = age, reverse = True)\n>>> triSimpsons\n [{'Prenom': 'Homer', 'age estim\u00e9': '38'},\n {'Prenom': 'Marge', 'age estim\u00e9': '37'},\n {'Prenom': 'Bart', 'age estim\u00e9': '10'},\n {'Prenom': 'Lisa', 'age estim\u00e9': '8'},\n {'Prenom': 'Maggie', 'age estim\u00e9': '1'}]\n
Exercice 1
\u00c9nonc\u00e9CorrectionTrier les joueurs du Top14 par taille.
>>> def taillePlayer(player) :\n return int(player['Taille'])\n>>> joueurs_taille_croissant = sorted(joueurs, key = taillePlayer)\n
Exercice 2
\u00c9nonc\u00e9CorrectionTrier les joueurs du Top14 par poids.
>>> def poidsPlayer(player) :\n return int(player['Poids'])\n>>> joueurs_poids_croissant = sorted(joueurs, key = poidsPlayer)\n
Exercice 3
\u00c9nonc\u00e9CorrectionTrier les joueurs de Bordeaux suivant leur Indice de Masse Corporelle (IMC )
>>> def IMC(player):\n masse = int(player['Poids'])\n taille_m = int(player['Taille']) / 100\n return masse / taille_m**2\n>>> joueursUBB = [player for player in joueurs if player['Equipe'] == 'Bordeaux']\n>>> joueursUBB_tri = sorted(joueursUBB, key = IMC)\n
"},{"location":"T5_Traitement_de_donnees/5.2_Trier_des_donnees/cours/#3-recherche-des-joueurs-de-profil-physique-similaire","title":"3. Recherche des joueurs de profil physique similaire","text":""},{"location":"T5_Traitement_de_donnees/5.2_Trier_des_donnees/cours/#31-distance-entre-deux-joueurs","title":"3.1 Distance entre deux joueurs","text":"Construire une fonction distance(joueur1, joueur2)
qui renvoie la somme des carr\u00e9s des diff\u00e9rences de tailles et de poids entre les joueurs joueur1
et joueur2
:
Cette fonction nous permettra d'estimer la diff\u00e9rence morphologique entre deux joueurs.
Utilisation :
>>> distance(joueurs[23], joueurs[31])\n244\n
V\u00e9rification :
>>> joueurs[23]\n{'Equipe': 'Agen', 'Nom': 'Alban CONDUCH\u00c9', 'Poste': 'Centre', 'Date de naissance': '29/10/1996', 'Taille': '190', 'Poids': '102'}\n>>> joueurs[31]\n{'Equipe': 'Agen', 'Nom': 'JJ TAULAGI', 'Poste': 'Arri\u00e8re', 'Date de naissance': '18/06/1993', 'Taille': '180', 'Poids': '90'}\n
\\((102-90)^2+(190-180)^2=244\\)
r\u00e9ponsedef distance(joueur1,joueur2):\n p1 = int(joueur1['Poids'])\n p2 = int(joueur2['Poids'])\n t1 = int(joueur1['Taille'])\n t2 = int(joueur2['Taille'])\n return (p1-p2)**2+(t1-t2)**2\n
"},{"location":"T5_Traitement_de_donnees/5.2_Trier_des_donnees/cours/#32-distance-des-joueurs-avec-baptiste-serin","title":"3.2 Distance des joueurs avec Baptiste Serin","text":"Retrouvons d'abord le num\u00e9ro de Baptiste Serin dans notre classement de joueurs :
>>> for k in range(len(joueurs)) :\n if joueurs[k]['Nom'] == 'Baptiste SERIN' :\n print(k)\n530\n
>>> joueurs[530]\n {'Equipe': 'Toulon',\n 'Nom': 'Baptiste SERIN',\n 'Poste': 'M\u00eal\u00e9e',\n 'Date de naissance': '20/06/1994',\n 'Taille': '180',\n 'Poids': '79'}\n
Baptiste SERIN est donc le joueur num\u00e9ro 530.
Cr\u00e9er une fonction distanceSerin
qui prend en param\u00e8tre un joueur et qui renvoie sa diff\u00e9rence avec Baptiste Serin.
Utilisation :
>>> distanceSerin(joueurs[18])\n745\n
r\u00e9ponse def distanceSerin(joueur):\n return distance(joueurs[530], joueur)\n
Classer l'ensemble des joueurs du Top14 suivant leur diff\u00e9rence morphologique avec Baptiste Serin (du plus proche au plus \u00e9loign\u00e9).
r\u00e9ponse>>> joueurs_VS_Serin = sorted(joueurs, key = distanceSerin)\n>>> joueurs_VS_Serin\n
"},{"location":"T5_Traitement_de_donnees/5.3_Pandas/cours/","title":"5.3 Utilisation du module Pandas","text":""},{"location":"T5_Traitement_de_donnees/5.3_Pandas/cours/#1-introduction-et-premiere-dataframe","title":"1. Introduction et premi\u00e8re dataframe","text":"Le module csv
utilis\u00e9 pr\u00e9c\u00e9demment se contente de lire les donn\u00e9es structur\u00e9es. Il ne fait aucun effort particulier pour analyser les donn\u00e9es. Nous nous en sommes aper\u00e7us lorsqu'il a fallu convertir par int()
toutes les valeurs num\u00e9riques, qui \u00e9taient interpr\u00e9t\u00e9es comme des cha\u00eenes de caract\u00e8res. La biblioth\u00e8que pandas est par contre sp\u00e9cialement con\u00e7ue pour l'analyse des donn\u00e9es (data analysis) : elle est donc naturellement bien plus performante.
Importation du module pandas
L'import se fait classiquement par :
import pandas as pd \n
Le type de variable dans lequel pandas
va stocker les donn\u00e9es s'appelle une dataframe, qui sera souvent abr\u00e9g\u00e9e par df
.
Nous allons retravailler avec le fichier top14.csv
.
Premi\u00e8re dataframe
Nos donn\u00e9es seront ensuite import\u00e9es dans la dataframe df
par l'instruction :
df = pd.read_csv('top14.csv', encoding = 'utf-8') \n
>>> type(df)\n<class 'pandas.core.frame.DataFrame'>\n
"},{"location":"T5_Traitement_de_donnees/5.3_Pandas/cours/#2-observation-des-donnees","title":"2. Observation des donn\u00e9es","text":"Que contient la variable df
?
>>> df\n Equipe Nom Poste Date de naissance Taille Poids\n0 Agen Anton PEIKRISHVILI Pilier 18/09/1987 183 122\n1 Agen Dave RYAN Pilier 21/04/1986 183 116\n2 Agen Giorgi TETRASHVILI Pilier 31/08/1993 177 112\n3 Agen Kamaliele TUFELE Pilier 11/10/1995 182 123\n4 Agen Malino VANA\u00cf Pilier 04/05/1993 183 119\n.. ... ... ... ... ... ...\n590 Toulouse Werner KOK Ailier 27/01/1993 177 78\n591 Toulouse Yoann HUGET Ailier 02/06/1987 190 97\n592 Toulouse Matthis LEBEL Arri\u00e8re 25/03/1999 185 91\n593 Toulouse Maxime M\u00c9DARD Arri\u00e8re 16/11/1986 180 85\n594 Toulouse Thomas RAMOS Arri\u00e8re 23/07/1995 178 86\n\n[595 rows x 6 columns]\n
Les donn\u00e9es sont pr\u00e9sent\u00e9es dans l'ordre originel du fichier.
"},{"location":"T5_Traitement_de_donnees/5.3_Pandas/cours/#21-structure-globale-des-donnees","title":"2.1 Structure globale des donn\u00e9es","text":"La structure des donn\u00e9es : info
>>> df.info()\n<class 'pandas.core.frame.DataFrame'>\nRangeIndex: 595 entries, 0 to 594\nData columns (total 6 columns):\n # Column Non-Null Count Dtype \n--- ------ -------------- ----- \n 0 Equipe 595 non-null object\n 1 Nom 595 non-null object\n 2 Poste 595 non-null object\n 3 Date de naissance 595 non-null object\n 4 Taille 595 non-null int64 \n 5 Poids 595 non-null int64 \ndtypes: int64(2), object(4)\nmemory usage: 28.0+ KB\n
On peut y constater une tr\u00e8s bonne nouvelle : les donn\u00e9es num\u00e9riques sont reconnues comme telles (type int64
).
D'apr\u00e8s la commande pr\u00e9c\u00e9dente, il y a 595 entr\u00e9es dans notre fichier de donn\u00e9es. L'acc\u00e8s \u00e0 une fiche particuli\u00e8re se fera avec la commande loc
.
Acc\u00e8s \u00e0 une fiche : loc
>>> df.loc[312]\nEquipe Lyon\nNom Charlie NGATAI\nPoste Centre\nDate de naissance 17/08/1990\nTaille 188\nPoids 103\nName: 312, dtype: object\n
"},{"location":"T5_Traitement_de_donnees/5.3_Pandas/cours/#23-premieres-et-dernieres-lignes","title":"2.3 Premi\u00e8res et derni\u00e8res lignes","text":"Il est toutefois possible d'avoir uniquement les premi\u00e8res lignes du fichier avec la commande head()
et les derni\u00e8res du fichier avec la commande tail()
. Ces commandes peuvent recevoir en param\u00e8tre un nombre entier :
Les premi\u00e8res lignes du fichier : head
>>> df.head()\n Equipe Nom Poste Date de naissance Taille Poids\n0 Agen Anton PEIKRISHVILI Pilier 18/09/1987 183 122\n1 Agen Dave RYAN Pilier 21/04/1986 183 116\n2 Agen Giorgi TETRASHVILI Pilier 31/08/1993 177 112\n3 Agen Kamaliele TUFELE Pilier 11/10/1995 182 123\n4 Agen Malino VANA\u00cf Pilier 04/05/1993 183 119\n\n>>> df.head(2)\n Equipe Nom Poste Date de naissance Taille Poids\n0 Agen Anton PEIKRISHVILI Pilier 18/09/1987 183 122\n1 Agen Dave RYAN Pilier 21/04/1986 183 116\n
Les derni\u00e8res lignes du fichier : tail
>>> df.tail()\n Equipe Nom Poste Date de naissance Taille Poids\n590 Toulouse Werner KOK Ailier 27/01/1993 177 78\n591 Toulouse Yoann HUGET Ailier 02/06/1987 190 97\n592 Toulouse Matthis LEBEL Arri\u00e8re 25/03/1999 185 91\n593 Toulouse Maxime M\u00c9DARD Arri\u00e8re 16/11/1986 180 85\n594 Toulouse Thomas RAMOS Arri\u00e8re 23/07/1995 178 86\n\n>>> df.tail(3)\n Equipe Nom Poste Date de naissance Taille Poids\n592 Toulouse Matthis LEBEL Arri\u00e8re 25/03/1999 185 91\n593 Toulouse Maxime M\u00c9DARD Arri\u00e8re 16/11/1986 180 85\n594 Toulouse Thomas RAMOS Arri\u00e8re 23/07/1995 178 86\n
"},{"location":"T5_Traitement_de_donnees/5.3_Pandas/cours/#3-analyse-automatique-et-filtrage","title":"3. Analyse automatique et filtrage","text":""},{"location":"T5_Traitement_de_donnees/5.3_Pandas/cours/#31-extraction-dune-colonne","title":"3.1 Extraction d'une colonne","text":"L'id\u00e9e g\u00e9n\u00e9rale est que l'on va cr\u00e9er de nouveaux objets contenant uniquement les renseignements qui nous int\u00e9ressent.
Extraction d'une colonne : df[colonne]
Pour cr\u00e9er une liste contenant uniquement les donn\u00e9es num\u00e9riques de la colonne poids
, il suffit d'\u00e9crire :
poids = df['Poids']\n
La variable poids
est un objet de type Series
(assimilable \u00e0 une liste) qui va pouvoir \u00eatre exploit\u00e9e tr\u00e8s facilement.
On peut d'ailleurs acc\u00e9der \u00e0 un \u00e9l\u00e9ment particulier de cette variable :
>>> poids[15]\n114\n
On confirme donc une excellente nouvelle : les poids sont bien consid\u00e9r\u00e9s nativement comme des nombres. On peut donc se servir de mani\u00e8re tr\u00e8s intuitive de cette fonctionnalit\u00e9 pour faire des graphiques tr\u00e8s facilement, sans conversion comme dans le module csv
!
Pour trouver le poids minimal de cette s\u00e9rie, on utilisera naturellement la fonction min
:
>>> min(poids)\n70\n
Pour tracer notre nuage de points poids-taille, le code sera donc simplement :
import matplotlib.pyplot as plt\nX = df['Poids']\nY = df['Taille']\nplt.plot(X, Y, 'ro')\nplt.show()\n
"},{"location":"T5_Traitement_de_donnees/5.3_Pandas/cours/#32-tri-et-analyse-automatique-des-donnees","title":"3.2 Tri et Analyse automatique des donn\u00e9es","text":"L'interpr\u00e9tation num\u00e9rique permet \u00e0 pandas
d'analyser automatiquement les donn\u00e9es, avec notamment la fonction describe()
.
R\u00e9sum\u00e9 des donn\u00e9es num\u00e9riques : describe
>>> df['Taille'].describe()\ncount 595.000000\nmean 186.559664\nstd 7.572615\nmin 169.000000\n25% 181.000000\n50% 186.000000\n75% 192.000000\nmax 208.000000\nName: Taille, dtype: float64\n
On voit donc que les principaux indicateurs statistiques sont propos\u00e9s.
D'ailleurs, on peut tr\u00e8s facilement tracer des boites \u00e0 moustaches avec la fonction boxplot()
.
graph_taille = df.boxplot(\"Taille\")\ngraph_taille.plot()\nplt.show()\n
Pour les donn\u00e9es non-num\u00e9riques, la commande describe()
n'est que peu d'utilit\u00e9. Elle renseigne toutefois la valeur la plus fr\u00e9quente (en statistiques, le mode ou valeur modale) gr\u00e2ce \u00e0 describe().top
.
Valeur modale de donn\u00e9es non-num\u00e9riques : describe().top
>>> df['Poste'].describe().top\n'3\u00e8me ligne'\n
Pour avoir un d\u00e9tail plus pr\u00e9cis de la r\u00e9partition des donn\u00e9es, on peut utiliser value_counts
:
R\u00e9partition des valeurs : value_counts
>>> df['Poste'].value_counts()\n3\u00e8me ligne 111\nPilier 110\n2\u00e8me ligne 74\nCentre 71\nAilier 64\nTalonneur 50\nM\u00eal\u00e9e 42\nOuverture 38\nArri\u00e8re 35\nName: Poste, dtype: int64\n
Il est possible aussi de trier la dataframe en lui indiquant la colonne de tri :
Trier les donn\u00e9es : sort_values
>>> classement_par_taille = df.sort_values(by='Taille', ascending = True)\n
"},{"location":"T5_Traitement_de_donnees/5.3_Pandas/cours/#4-filtres-et-recherches","title":"4. Filtres et recherches","text":"Le principe du filtrage va \u00eatre de cr\u00e9er une nouvelle dataframe ne contenant que des lignes correspondant \u00e0 un certain crit\u00e8re.
Filtrage des lignes : df[bool\u00e9en]
Comment cr\u00e9er une dataframe ne contenant que les joueurs de l'UBB ? L'id\u00e9e syntaxique est d'\u00e9crire \u00e0 l'int\u00e9rieur de df[]
le test qui permettra le filtrage.
>>> UBB = df[df['Equipe'] == 'Bordeaux']\n
Le bool\u00e9en df['Equipe'] == 'Bordeaux'
doit se comprendre ainsi : on ne veut garder que les joueurs dont le champ Equipe
est \u00e9gal \u00e0 'Bordeaux'
. >>> UBB\n Equipe Nom Poste Date de naissance Taille Poids\n80 Bordeaux Jefferson POIROT Pilier 01/11/1992 181 117\n81 Bordeaux Lasha TABIDZE Pilier 04/07/1997 185 117\n82 Bordeaux Laurent DELBOULB\u00c8S Pilier 17/11/1986 181 106\n83 Bordeaux Lekso KAULASHVILI Pilier 27/08/1992 187 120\n84 Bordeaux Peni RAVAI Pilier 16/06/1990 185 119\n...\n
Exercice 1
Cr\u00e9er une dataframe grands
qui contient tous les joueurs mesurant plus de 2 m\u00e8tres (inclus).
>>> grands = df[df['Taille'] >= 200]\n
Pour effectuer des op\u00e9rations sur les bool\u00e9ens, on utilisera le symbole &
pour le ET et |
pour le OU.
Exercice 2
Cr\u00e9er une dataframe grands_et_gros
qui contient tous les joueurs mesurant plus de 2 m\u00e8tres (inclus) et pesant plus de 120 kg (inclus).
>>> grands_gros = df[(df['Taille'] >= 200) & (df['Poids'] >= 120)]\n
Autre solution, en utilisant la datadframe grands
de l'exercice 1 :
>>> grands_gros = grands[grands['Poids'] >= 120]\n
Exercice 3
Trouver en une seule ligne le joueur le plus l\u00e9ger du Top14.
Correction>>> df[df['Poids'] == min(df['Poids'])]\n Equipe Nom Poste Date de naissance Taille Poids\n491 Racing92 Teddy IRIBAREN M\u00eal\u00e9e 25/09/1990 170 70\n
ou bien
>>> df.sort_values(by='Poids', ascending=True).head(1)\n
Exercice 4
Tracer le nuage de point poids-taille comme pr\u00e9c\u00e9demment, mais en marquant d'un point bleu les 2\u00e8mes ligne et d'un point rouge les piliers.
Correctionimport pandas as pd\nimport matplotlib.pyplot as plt\n\ndf = pd.read_csv('top14.csv', encoding = 'utf-8') \n\nX = df['Poids']\nY = df['Taille']\nplt.plot(X, Y, 'ro')\n\n\nX = df[df['Poste'] == '2\u00e8me ligne']['Poids']\nY = df[df['Poste'] == '2\u00e8me ligne']['Taille']\nplt.plot(X, Y, 'bo')\n\n\nX = df[df['Poste'] == 'Pilier']['Poids']\nY = df[df['Poste'] == 'Pilier']['Taille']\nplt.plot(X, Y, 'go')\n
"},{"location":"T5_Traitement_de_donnees/5.3_Pandas/cours/#5-modification-de-la-structure-rajout-dune-colonne","title":"5. Modification de la structure : rajout d'une colonne","text":"Afin de pouvoir trier les joueurs suivant de nouveaux crit\u00e8res, nous allons rajouter un champ pour chaque joueur. Prenons un exemple stupide : fabriquons un nouveau champ 'Poids apr\u00e8s les vacances'
qui contiendra le poids des joueurs augment\u00e9 de 8 kg. Ceci se fera simplement par :
Rajout d'une colonne
>>> df['Poids apr\u00e8s les vacances'] = df['Poids'] + 8\n
On voit apparaitre dans la dataframe df
une nouvelle colonne
>>> df.head()\n Equipe Nom Poste ... Taille Poids Poids apr\u00e8s les vacances\n0 Agen Anton PEIKRISHVILI Pilier ... 183 122 130\n1 Agen Dave RYAN Pilier ... 183 116 124\n2 Agen Giorgi TETRASHVILI Pilier ... 177 112 120\n3 Agen Kamaliele TUFELE Pilier ... 182 123 131\n4 Agen Malino VANA\u00cf Pilier ... 183 119 127\n\n[5 rows x 7 columns]\n
Pour supprimer cette colonne sans int\u00e9r\u00eat, il suffit de faire :
del df['Poids apr\u00e8s les vacances'] \n
Exercice 5
Q1. Cr\u00e9er une colonne contenant l'IMC de chaque joueur.
Q2. Cr\u00e9er une nouvelle dataframe contenant tous les joueurs du Top14 class\u00e9s par ordre d'IMC croissant.
"},{"location":"T5_Traitement_de_donnees/5.3_Pandas/cours/#6-retour-sur-le-knn","title":"6.\u00a0Retour sur le KNN","text":"Comme dans ce cours, nous allons construire une fonction conseil_poste
recevant en param\u00e8tres :
df
: la dataframe contenant nos donn\u00e9espoids
: le poids du joueur Xtaille
: la taille du joueur Xk
: le nombre de joueurs les plus proches sur lequel on se base pour faire la pr\u00e9dictionqui renvoie le poste le plus compatible avec la morphologie de X.
Il est maintenant possible de coder cette fonction beaucoup plus simplement (mais alors VRAIMENT beaucoup) qu'avec le module csv
.
Il va nous suffir de :
k
premiers \u00e9l\u00e9ments.k
premiers \u00e9lements.Algorithme KNN
import pandas as pd\n\ndf = pd.read_csv('top14.csv', encoding = 'utf-8') \n\ndef conseil_poste(df, poids, taille, k):\n ...\n ...\n ...\n ...\n
>>> conseil_poste(df, 70, 160, 10)\n'M\u00eal\u00e9e'\n>>> conseil_poste(df, 130, 160, 10)\n'Pilier'\n
"},{"location":"T5_Traitement_de_donnees/5.3_Pandas/exercices/","title":"Analyse des passagers du Titanic","text":"Nous allons travailler avec le fichier titanic.csv
.
Dans la barre d'adresse de son navigateur, taper localhost
ou bien 127.0.0.1
.
Si aucune page n'appara\u00eet, c'est que le serveur n'est pas d\u00e9marr\u00e9.
"},{"location":"T6_IHM_Web/pagesperso/#12-demarrer-le-serveur","title":"1.2 D\u00e9marrer le serveur","text":"Dans un terminal, taper
sudo /opt/lampp/lampp start
Dans un terminal,
ip addr
regarder 4 lignes avant la fin, chercher une adresse IP commen\u00e7ant par 192.168.1.XXX
.
Dans un terminal ouvert depuis le dossier contenant ses pages :
sudo cp mapage.html /opt/lampp/htdocs/
Si on veut tout copier :
sudo cp * /opt/lampp/htdocs/
Nous allons tout d'abord consid\u00e9rer le cas o\u00f9 le serveur renvoie une page unique, identique pour tous les utilisateurs. De plus, l'utilisateur ne pourra pas agir sur sa page : il n'y a aucune interactivit\u00e9.
Exemple de page statique c\u00f4t\u00e9 serveur et c\u00f4t\u00e9 utilisateur :
html
pur","text":"Lorsque le client demande au serveur le contenu d'une page web, celui-ci lui renvoie, dans le cas le plus simple, une simple page html
. html
est un langage dit \u00ab \u00e0 balises \u00bb. Ce n'est pas \u00e0 proprement parler un langage de programmation, mais plut\u00f4t un langage de description de contenu. Il a \u00e9t\u00e9 invent\u00e9 en 1992 par Tim Berners-Lee. La version actuellement utilis\u00e9e est le html5
.
Exemple de page web minimale
<!DOCTYPE html>\n<html lang='fr'>\n <head>\n <meta charset=\"utf-8\">\n <title>Un titre tr\u00e8s original</title>\n </head>\n\n <body>\n <p>Ceci est le texte introductif de ma page.</p>\n <p>\n <h1> Ceci est un titre de niveau 1 </h1>\n Mais sans rien d'int\u00e9ressant.\n <h2> Ceci est un titre de niveau 2 </h2>\n <ul>\n <li> le d\u00e9but d'une liste indent\u00e9e </li>\n <li> la suite ... </li>\n </ul> \n Pour apprendre le fonctionnement des balises, voir <a href=\"https://developer.mozilla.org/fr/docs/Apprendre/HTML/Introduction_%C3%A0_HTML/Getting_started\"> ici</a> par exemple !\n </p>\n </body>\n</html>\n
Vous pouvez contempler ici le rendu de cette magnifique page.
Exercice 1
\u00c9nonc\u00e9mapage.html
.html
+ css
","text":"L'acronyme css
signifie Cascading Style Sheets. L'id\u00e9e est de regrouper dans un seul fichier toutes les informations relatives \u00e0 la mise en forme des \u00e9l\u00e9ments de la page html. De mani\u00e8re tr\u00e8s simplifi\u00e9e, on peut dire que le fichier html
s'occupe du fond tandis que le fichier css
s'occupe de la forme.
Le fichier css
(souvent nomm\u00e9 style.css
et appel\u00e9 feuille de style) doit \u00eatre r\u00e9f\u00e9renc\u00e9 au d\u00e9but du fichier html
, au sein de la balise <head>
.
Exemple de couple html
/ css
minimal
fichier index.html
:
<!DOCTYPE html>\n<html>\n <head>\n <meta charset=\"utf-8\">\n <title>page test</title>\n <link href=\"style.css\" rel=\"stylesheet\" type=\"text/css\" />\n </head>\n <body>\n <p>\n <h1> Ceci est un titre de niveau 1 </h1>\n Mais sans rien d'int\u00e9ressant.\n <h2> Ceci est un titre de niveau 2 </h2>\n </p>\n </body>\n</html>\n
fichier style.css
:
html {\nfont-size: 15px;\nfont-family: sans-serif;\nbackground-color: lightgray; }\n\nh1 {\ncolor: red;\n}\n
Vous pouvez contempler ici le nouveau rendu de cette encore plus magnifique page.
En savoir plus
Exercice 2
Reprenez votre page de l'exercice 1 et rajoutez une feuille de style.
Exercice 3
F12
)Jusqu'\u00e0 pr\u00e9sent, la page web envoy\u00e9e par le serveur est :
Le JavaScript va venir r\u00e9gler le probl\u00e8me n\u00b02 : il est possible de fabriquer une page sur laquelle le client va pouvoir agir localement, sans avoir \u00e0 redemander une nouvelle page au serveur.
Invent\u00e9 en 1995 par Brendan Eich pour le navigateur Netscape, le langage JavaScript s'est impos\u00e9 comme la norme aupr\u00e8s de tous les navigateurs pour apporter de l'interactivit\u00e9 aux pages web.
Exemple de couple html
/ javascript
minimal
Notre fichier index.html
fait r\u00e9f\u00e9rence, au sein d'une balise <script>
, \u00e0 un fichier externe script.js
qui contiendra notre code JavaScript.
fichier index.html
:
<!DOCTYPE html>\n<html>\n <head>\n <meta charset=\"utf-8\">\n <title>un peu d'action</title>\n <link href=\"style.css\" rel=\"stylesheet\" type=\"text/css\" />\n </head>\n <body>\n <script src=\"script.js\"></script>\n <p>\n <h2>Une page web extr\u00eamement dynamique</h2>\n </p>\n <div>\n\n <label>Changez la couleur d'arri\u00e8re-plan:</label>\n\n <button type=\"button\" onclick=\"choix('yellow');\">jaune</button>\n\n <button type=\"button\" onclick=\"choix('green');\">vert</button>\n\n <button type=\"button\" onclick=\"choix('purple');\">violet</button> \n </div>\n <div>\n <p>\n En JavaScript, le nom de la couleur choisie est :\n </p>\n <p id=\"resultat\"></p>\n </div>\n </body>\n</html>\n
fichier script.js
:
function choix(color){\ndocument.body.style.background = color;\ndocument.getElementById(\"resultat\").innerHTML=color;\n}\n
Le r\u00e9sultat de cette page peut \u00eatre consult\u00e9 ici. (oui, j'ai confondu le jaune et le rose)
Commentaires
button
, l'attribut onclick
re\u00e7oit le nom d'une fonction d\u00e9clar\u00e9e \u00e0 l'int\u00e9rieur du fichier script.js
, ici la fonction choix()
.La puissance du JavaScript permet de r\u00e9aliser aujourd'hui des interfaces utilisateurs tr\u00e8s complexes au sein d'un navigateur, \u00e9quivalentes \u00e0 celles produites par des logiciels externes (pensez \u00e0 Discord, par ex.). Bien s\u00fbr, dans ces cas complexes, le serveur est aussi sollicit\u00e9 pour modifier la page, comme nous le verrons en partie 3.
En savoir plus
Exercice 4
Rappelons que toutes les pages que nous avons cr\u00e9\u00e9es jusqu'\u00e0 pr\u00e9sent sont uniform\u00e9ment envoy\u00e9es par le serveur au client. Aucune \u00abpr\u00e9paration\u00bb de la page en amont n'a lieu sur le serveur, aucun dialogue n'a lieu avec le serveur une fois que la page a \u00e9t\u00e9 livr\u00e9e. \u00c9videmment, si le web \u00e9tait comme ceci, il ne serait qu'une gigantesque biblioth\u00e8que en consultation seule (ce fut le cas pendant longtemps, et ce qui n'\u00e9tait d\u00e9j\u00e0 pas si mal).
Les langages serveurs, parmi lesquels PHP (pr\u00e9sent sur environ 80% des serveurs), Python (via le framework Django), Java, Ruby, C#, permettent de rajouter de l'interactivit\u00e9 c\u00f4t\u00e9 serveur.
Il convient de rappeler la diff\u00e9rence fondamentale entre une page statique (c\u00f4t\u00e9 serveur) et une page dynamique (c\u00f4t\u00e9 serveur) :
"},{"location":"T6_IHM_Web/6.1_Interactions_page_web/cours/#31-page-statique-cote-serveur","title":"3.1 Page statique (c\u00f4t\u00e9 serveur) :","text":"Lors d'une requ\u00eate d'un client vers un serveur, si le client demande la page index.html
, une copie exacte du fichier index.html
est transmise au client sur sa machine.
Exemple : la page http://glassus1.free.fr/interesting.html que vous avez d\u00e9j\u00e0 consult\u00e9e se trouve telle quelle sur le serveur mis \u00e0 disposition par Free pour l'h\u00e9bergement des pages personnelles :
Depuis votre navigateur, l'affichage du code-source (par Ctrl-U) vous donnera le fichier html tel qu'il \u00e9tait stock\u00e9 sur le serveur.
"},{"location":"T6_IHM_Web/6.1_Interactions_page_web/cours/#32-page-dynamique-cote-serveur","title":"3.2 Page dynamique (c\u00f4t\u00e9 serveur) :","text":"Lors d'une requ\u00eate d'un client vers un serveur, si le client demande la page test.php
, un code html est g\u00e9n\u00e9r\u00e9 \u00e0 partir du fichier test.php
puis est transmise au client sur sa machine. Le fichier transmis ne contient plus de balises php
, il ne comporte que des balises html
classiques.
Exemple : la consultation de la page http://glassus1.free.fr/test.php va renvoyer la page suivante :
dont le code-source est :
Notez bien que ce code-source ne contient que du html
.
Allons regarder cette page du c\u00f4t\u00e9 du serveur :
Le contenu de cette page est :
<!DOCTYPE html>\n<html>\n <head>\n <meta charset=\"utf-8\" />\n <title>Quel jour sommes-nous</title>\n </head>\n <body>\n <p>\n<?php\n $date = date(\"d-m-Y\");\n Print(\"Nous sommes le $date\");\n ?>\n </p>\n</body>\n</html>\n
On y rep\u00e8re la balise <?php>
:
<?php\n $date = date(\"d-m-Y\");\n Print(\"Nous sommes le $date\");\n ?>\n
Ce code php
a donc g\u00e9n\u00e9r\u00e9, lors de l'appel au serveur, le code html
: Nous sommes le 13-04-2020\n
Vous pouvez tester du code PHP et la page g\u00e9n\u00e9r\u00e9e par exemple sur ce site.
Voil\u00e0 comment un serveur peut adapter la page qu'il renvoie, suivant l'utilisateur qui la demande. Nous verrons prochainement comment par des requ\u00eates le client peut envoyer des param\u00e8tres au serveur, et comment celui-ci modifie sa r\u00e9ponse en cons\u00e9quence.
En savoir plus : https://www.php.net/manual/fr/tutorial.firstpage.php
"},{"location":"T6_IHM_Web/6.2_Protocole_HTTP/cours/","title":"6.2 Protocole HTTP : \u00e9tude du chargement d'une page web","text":""},{"location":"T6_IHM_Web/6.2_Protocole_HTTP/cours/#le-protocole-http-des-requetes-et-des-reponses","title":"Le protocole HTTP : des requ\u00eates et des r\u00e9ponses","text":"HTTP (HyperText Transfer Protocol) est le protocole qui r\u00e9git la communication entre :
Prenons pour exemple la requ\u00eate d'un navigateur vers la page http://glassus1.free.fr/interesting.html
interesting.html
, stock\u00e9e sur le serveur glassus1.free.fr
. glassus1.free.fr
(qui est en fait un sous-domaine du serveur des pages personnelles de l'op\u00e9rateur Free). Ici, l'adresse IP sera 212.27.63.111
(on la retrouvera dans la capture de la fen\u00eatre d'Outils de dev\u00e9loppement).212.27.63.111
.Observons \u00e0 partir de l'Inspecteur d'\u00e9l\u00e9ment d'un navigateur (ici Firefox) les informations qui transitent lors de la requ\u00eate et de la r\u00e9ponse.
http://glassus1.free.fr/interesting.html
a g\u00e9n\u00e9r\u00e9 un code de r\u00e9ponse 200 OK, ce qui signifie que la requ\u00eate a \u00e9t\u00e9 trait\u00e9e et que la r\u00e9ponse contenant la page a \u00e9t\u00e9 envoy\u00e9e. Vous pouvez trouver \u00e0 l'adresse https://developer.mozilla.org/fr/docs/Web/HTTP/Status la totalit\u00e9 des codes de r\u00e9ponse possibles. Citons par exemple : http://glassus1.free.fr/interesting.fr
(qui est une page ultra-basique, et n'\u00e9volue pas). Pour r\u00e9-obtenir un code 200, il faut faire un hard-refresh en appuyant sur Maj pendant l'actualisation.HTTP/1.1 200 OK\nDate: Wed, 22 Apr 2020 08:02:01 GMT\nServer: Apache/ProXad [Jan 23 2019 19:58:42]\nLast-Modified: Sun, 12 Apr 2020 16:39:55 GMT\nETag: \"15d7c75-7c-5e93445b\"\nConnection: close\nAccept-Ranges: bytes\nContent-Length: 124\nContent-Type: text/html\n
<!DOCTYPE html>\n<html>\n<head>\n<title>Waouh</title>\n</head>\n<body>\nCeci est vraiment une jolie page web.\n</body>\n</html>\n
Remarque : on peut observer que le navigateur a aussi effectu\u00e9 (de sa propre initiative) une requ\u00eate vers un fichier favicon.ico
qui est l'icone de la page web dans les onglets du navigateur ou la barre de favoris. Ce fichier \u00e9tait bien pr\u00e9sent sur le serveur (ce n'est pas toujours le cas), il a donc \u00e9t\u00e9 envoy\u00e9 dans la r\u00e9ponse du serveur.
De mani\u00e8re g\u00e9n\u00e9rale, une requ\u00eate vers un site web moins \u00e9l\u00e9mentaire va occasionner une multitude de r\u00e9ponses.
Par exemple, l'appel au site www.lyceemauriac.fr
g\u00e9n\u00e8re 129 requ\u00eates/r\u00e9ponses diff\u00e9rentes, compos\u00e9es de fichiers html, css, js, de fichiers de fontes woff2, d'images jpg, png...
Consid\u00e9rons le formulaire suivant, inclus dans une page html ouverte dans le navigateur du client :
Le mot de passe est :\n<form action=\"cible2.php\" method=\"get\">\n<p>\n <input type=\"password\" name=\"pass\" /> \n <input type=\"submit\" value=\"Valider\" />\n</p>\n</form>\n
Aper\u00e7u :
Explications :
cible2.php
est le fichier sur le serveur qui recevra les param\u00e8tres contenus dans le formulaire.pass
et sera de type password
, ce qui signifie qu'on n'affichera pas les caract\u00e8res tap\u00e9s par l'utilisateur. On aurait pu aussi avoir un type :text
: le texte s'affiche en clair (pour les login par ex) radio
: pour une s\u00e9lection (d'un seul \u00e9l\u00e9ment)checkbox
: pour une s\u00e9lection (\u00e9ventuellement multiple)submit
) des param\u00e8tres (ici un seul, la variable pass
) au serveur.Les param\u00e8tres pass\u00e9s au serveur par la m\u00e9thode GET sont transmis dans l'url de la requ\u00eate. Ils sont donc lisibles en clair par n'importe qui.
\u00c9videmment, c'est une m\u00e9thode catastrophique pour la transmission des mots de passe. Par contre, c'est une m\u00e9thode efficace pour acc\u00e9der directement \u00e0 une page particuli\u00e8re : ainsi l'url https://www.google.fr/search?q=bordeaux nous am\u00e8nera directement au r\u00e9sultat de la recherche Google sur le mot-cl\u00e9 \u00abbordeaux\u00bb.
"},{"location":"T6_IHM_Web/6.3_Get_Post_Formulaires/cours/#12-la-methode-post","title":"1.2. La m\u00e9thode POST","text":"Dans notre code de formulaire du 1.1, modifions l'attribut method
, auparavant \u00e9gal \u00e0 \"get\"
. Passons-le \u00e9gal \u00e0 \"post\"
:
Le mot de passe est :\n<form action=\"cible2.php\" method=\"post\">\n<p>\n <input type=\"password\" name=\"pass\" /> \n <input type=\"submit\" value=\"Valider\" />\n</p>\n</form>\n
"},{"location":"T6_IHM_Web/6.3_Get_Post_Formulaires/cours/#test_1","title":"Test :","text":"Les param\u00e8tres pass\u00e9s au serveur par la m\u00e9thode POST ne sont pas visibles dans l'url de la requ\u00eate. Ils sont contenus dans le corps de la requ\u00eate, mais non affich\u00e9s sur le navigateur.
Donc, la transmission du mot de passe est bien s\u00e9curis\u00e9e par la m\u00e9thode POST ?
Pas du tout ! Si le protocole de transmission est du http
et non pas du https
, n'importe qui interceptant le trafic peut lire le contenu de la requ\u00eate et y trouver le mot de passe en clair.
Exemple avec Wireshark :
Le contenu de la variable \"pass\"
est donc visible dans le contenu de la requ\u00eate.
Le passage en https
chiffre le contenu de la requ\u00eate et emp\u00eache donc la simple lecture du mot de passe.
POST : la m\u00e9thode POST doit \u00eatre utilis\u00e9e quand les param\u00e8tres \u00e0 envoyer :
Cette fen\u00eatre est caract\u00e9ristique de l'utilisation d'une m\u00e9thode POST.
Du c\u00f4t\u00e9 du serveur, le langage utilis\u00e9 (PHP, Java...) doit r\u00e9cup\u00e9rer les param\u00e8tres envoy\u00e9s pour modifier les \u00e9lements d'une nouvelle page, mettre \u00e0 jour une base de donn\u00e9es, etc. Comment sont r\u00e9cup\u00e9r\u00e9es ces valeurs ?
"},{"location":"T6_IHM_Web/6.3_Get_Post_Formulaires/cours/#exemple-en-php","title":"Exemple en PHP","text":"L'acronyme PHP signifie **P**HP : **H**ypertext **P**rocessor (c'est un acronyme r\u00e9cursif).
Notre exemple va contenir deux fichiers :
page1.html
, qui contiendra un formulaire et qui renverra, par la m\u00e9thode GET, un param\u00e8tre \u00e0 la page page2.php
.page2.php
, qui g\u00e9n\u00e8rera un code html
personnalis\u00e9 en fonction du param\u00e8tre re\u00e7u. page1.html
","text":"<!DOCTYPE html>\n<html>\n <head>\n <meta charset=\"utf-8\">\n <title>exemple</title>\n </head>\n <body>\n Votre OS actuel est un : \n<form action=page2.php method=\"get\">\n<p>\n <input type=\"radio\" name=\"OS\" value=\"Windows\"> Windows </input>\n <input type=\"radio\" name=\"OS\" value=\"MacOS\"> MacOS </input>\n <input type=\"radio\" name=\"OS\" value=\"GNU/Linux\"> GNU/Linux </input>\n</p>\n<p> \n <input type=\"submit\" value=\"Valider\" />\n</p>\n</form>\n </body>\n</html>\n
"},{"location":"T6_IHM_Web/6.3_Get_Post_Formulaires/cours/#page2php","title":"page2.php
","text":" <!DOCTYPE html>\n<html>\n <head>\n <meta charset=\"utf-8\" />\n <title>Le meilleur OS</title>\n </head>\n <body>\n <p>\n<?php\n if (isset($_GET['OS']))\n {\n Print(\"Vous avez raison, \");\n echo $_GET['OS'];\n Print(\" est le meilleur des OS.\");\n }\n ?>\n </p>\n\n</body>\n</html>\n
"},{"location":"T6_IHM_Web/6.3_Get_Post_Formulaires/cours/#detail-du-fonctionnement","title":"D\u00e9tail du fonctionnement :","text":"page1.html
, un formulaire de type boutons radio lui propose : OS
va recevoir la valeur choisie et va \u00eatre transmise par une requ\u00eate GET \u00e0 l'url donn\u00e9e par la variable action
d\u00e9finie en d\u00e9but de formulaire. Ici, le navigateur va donc demander \u00e0 acc\u00e9der \u00e0 la page page2.php?OS=MacOS
(par exemple)page2.php
va recevoir la demande d'acc\u00e8s \u00e0 la page ainsi que la valeur de la variable OS
. Dans le code PHP, on reconnait :isset($_GET['OS'])
qui v\u00e9rifie si le param\u00e8tre OS
a bien re\u00e7u une valeur.$_GET['OS']
qui r\u00e9cup\u00e8re cette valeur. Si la valeur avait \u00e9t\u00e9 transmise par m\u00e9thode POST (pour un mot de passe, par exemple), la variable aurait \u00e9t\u00e9 r\u00e9cup\u00e9r\u00e9e par $_POST['OS']
. Elle n'aurait par contre pas \u00e9t\u00e9 affich\u00e9e dans l'url de la page.page2.php?OS=MacOS
s'affiche sur le navigateur de l'utilisateur :L'exemple ci-dessus est un mauvais exemple : rien ne justifie l'emploi d'un serveur distant. L'affichage de ce message aurait tr\u00e8s bien pu se faire en local sur le navigateur du client, en Javascript par exemple.
L'envoi de param\u00e8tre \u00e0 un serveur distant est n\u00e9cessaire pour aller interroger une base de donn\u00e9es, par exemple (lorsque vous remplissez un formulaire sur le site de la SNCF, les bases de donn\u00e9es des horaires de trains, des places disponibles et de leurs tarifs ne sont pas h\u00e9berg\u00e9es sur votre ordinateur en local...).
La v\u00e9rification d'un mot de passe doit aussi se faire sur un serveur distant.
"},{"location":"T6_IHM_Web/6.3_Get_Post_Formulaires/cours/#exercice-attaque-par-force-brute-et-requete-get","title":"Exercice : attaque par force brute et requ\u00eate GET","text":""},{"location":"T6_IHM_Web/6.3_Get_Post_Formulaires/cours/#pre-requis-1-le-module-requests-en-python","title":"Pr\u00e9-requis 1 : le modulerequests
en python","text":"Le module requests
permet d'aller chercher le contenu d'une page web, suivant la syntaxe ci-dessous. Testez le code ci-dessous :
import requests\np = requests.get(\"http://glassus1.free.fr/interesting.html\", verify = False)\nprint(p.text)\n
La sortie en console est :
<!DOCTYPE html>\n<html>\n\n<head>\n\n<title>Waouh</title>\n</head>\n\n<body>\nCeci est vraiment une jolie page web.\n</body>\n\n</html>\n
Notre programme Python se comporte donc \u00abcomme un navigateur\u00bb : il se rend sur une page, effectue une requ\u00eate et r\u00e9cup\u00e8re la page renvoy\u00e9e.
"},{"location":"T6_IHM_Web/6.3_Get_Post_Formulaires/cours/#pre-requis-2-lextraction-dun-fichier-texte-sous-forme-de-liste","title":"Pr\u00e9-requis 2 : l'extraction d'un fichier texte sous forme de liste","text":"Le code ci-dessous permet de collecter dans une liste mots
l'ensemble des mots compris dans le fichier monfichiertexte.txt
(si celui-ci comprend un mot par ligne)
mots = open(\"monfichiertexte.txt\").read().splitlines()\n
"},{"location":"T6_IHM_Web/6.3_Get_Post_Formulaires/cours/#exercice","title":"Exercice :","text":"Votre objectif est de trouver le mot de passe demand\u00e9 sur la page http://glassus1.free.fr/exoBF.html
Vous allez vous appuyer sur un leak (fuite) tr\u00e8s c\u00e9l\u00e8bre de mots de passe , qui est le leak du site Rockyou. Dans la base de donn\u00e9es de ce site, 32 millions de mots de passe \u00e9taient stock\u00e9s en clair \u00af\\_(\u30c4)_/\u00af
.
Lorsque le site a \u00e9t\u00e9 pirat\u00e9 (par une injection SQL, voir le cours de Terminale), ces 32 millions de mots de passe se sont retrouv\u00e9s dans la nature. Ils sont aujourd'hui t\u00e9l\u00e9chargeables librement, et constituent un dictionnaire de 14 341 564 mots de passe diff\u00e9rents (car parmi les 32 millions d'utilisateurs, beaucoup utilisaient des mots de passe identiques). Ce fichier est t\u00e9l\u00e9chargeable ici, mais attention il p\u00e8se 134 Mo.
Nous allons utiliser un fichier beaucoup plus l\u00e9ger ne contenant que les 1000 premiers mots de passe : vous le trouverez \u00e0 l'adresse http://glassus1.free.fr/extraitrockyou.txt .
L'un de ces mots de passe est le mot de passe demand\u00e9 \u00e0 la page http://glassus1.free.fr/exoBF.html .
Lequel ?
Correctionimport requests\n\npage_error = requests.get(\"http://glassus1.free.fr/repBF.php?pass=\")\n\nliste_mdp = open(\"extraitrockyou.txt\").read().splitlines()\n\nurl = \"http://glassus1.free.fr/repBF.php?pass=\"\n\nfor mdp in liste_mdp:\n new_url = url + mdp\n print(new_url)\n page_tentative = requests.get(new_url)\n if page_tentative.text != page_error.text:\n print(\"Le mot de passe est le suivant :\", mdp)\n break\n
"},{"location":"T6_Mini-projets/05_Initiation_Pygame/","title":"Initiation \u00e0 Pygame","text":""},{"location":"T6_Mini-projets/05_Initiation_Pygame/#0-preambule","title":"0. Preambule","text":"pip3 install pygame
.Sur votre pc perso, vous pouvez utiliser le gestionnaire de packages de Thonny (Outils / G\u00e9rer les Paquets
)
Installation et param\u00e9trage de Github Desktop
import pygame, sys\nfrom pygame.locals import *\n\npygame.init()\n\nfenetre = pygame.display.set_mode((640, 480))\n\nfenetre.fill([10,186,181])\n\npygame.display.flip()\n\nwhile True :\n pass\n
Ce code devrait vous donner ceci :
Commentaires
sys
permettra de fermer le programme au niveau de l'OS par la commande sys.exit()
from pygame.locals import *
permettra d'utiliser des variables locales d\u00e9j\u00e0 d\u00e9finies par pygame
, comme MOUSEBUTTONDOWN
, par exemple.fenetre
, dans lequel nous viendrons coller de nouveaux \u00e9l\u00e9ments. \u00c9l\u00e9ments structurants d'un code pygame
:
pygame.init()
effectue une initialisation globale de tous les modules pygame
import\u00e9s. \u00c0 mettre au d\u00e9but du code.pygame.display.flip()
effectue un rafra\u00eechissement total de tous les \u00e9l\u00e9ments graphiques de la fen\u00eatre. \u00c0 mettre donc plut\u00f4t vers la fin du code.while True :
comme tr\u00e8s souvent dans les jeux, la structure essentielle est une boucle infinie dont on ne sortira que par une interruption syst\u00e8me (sys.exit()
) o\u00f9 lors de la bascule d'un bool\u00e9en. Pour l'instant, cette boucle est vide (pass
).Nous allons travailler avec le sprite ci-dessous, nomm\u00e9 perso.png
. Il est issu de https://openclassrooms.com/fr/courses/1399541-interface-graphique-pygame-pour-python/1399813-premieres-fenetres
T\u00e9l\u00e9chargez-le pour le mettre dans le m\u00eame dossier que votre code pygame
.
Vous pouvez trouver sur internet un grand nombre de sprites libres de droits, au format png
(donc g\u00e9rant la transparence), dans de multiples positions (ce qui permet de simuler des mouvements fluides). Ici nous travaillerons avec un sprite unique.
perso = pygame.image.load(\"perso.png\").convert_alpha()\n
La fonction convert_alpha()
est appel\u00e9e pour que soit correctement trait\u00e9 le canal de transparence (canal alpha) de notre image."},{"location":"T6_Mini-projets/05_Initiation_Pygame/#23-affichage-de-limage","title":"2.3. Affichage de l'image","text":"\u00c0 ce stade, perso
est un objet pygame
de type Surface
.
Afin de facilement pouvoir le d\u00e9placer, nous allons stocker la position de cet objet dans une variable position_perso
, qui sera de type rect
.
position_perso = perso.get_rect()\n
Pour afficher cette image, nous allons venir le superposer aux \u00e9l\u00e9ments graphiques d\u00e9j\u00e0 dessin\u00e9s (en l'occurence : rien) avec l'instruction blit()
: fenetre.blit(perso, position_perso)\n
\u25b8 r\u00e9capitulatif du code
import pygame, sys\nfrom pygame.locals import *\n\npygame.init()\n\nfenetre = pygame.display.set_mode((640, 480))\nfenetre.fill([10,186,181])\n\nperso = pygame.image.load(\"perso.png\").convert_alpha()\nposition_perso = perso.get_rect()\n\nfenetre.blit(perso, position_perso)\n\npygame.display.flip()\n\nwhile True :\n pass\n
Aper\u00e7u
"},{"location":"T6_Mini-projets/05_Initiation_Pygame/#3-gestion-des-evenements","title":"3. Gestion des \u00e9v\u00e8nements","text":"Lorsqu'un programme pygame
est lanc\u00e9, la variable interne pygame.event.get()
re\u00e7oit en continu les \u00e9v\u00e8nements des p\u00e9riph\u00e9riques g\u00e9r\u00e9s par le syst\u00e8me d'exploitation. Nous allons nous int\u00e9resser aux \u00e9v\u00e8nements de type KEYDOWN
(touche de clavier appuy\u00e9e) ou de type MOUSEBUTTONDOWN
(boutons de souris appuy\u00e9).
La gestion des \u00e9v\u00e8nements nous permettra de pouvoir enfin fermer proprement la fen\u00eatre Pygame, gr\u00e2ce au code suivant :
# routine pour pouvoir fermer \u00abproprement\u00bb la fen\u00eatre Pygame\nfor event in pygame.event.get():\n if event.type == pygame.QUIT:\n pygame.display.quit()\n sys.exit()\n
"},{"location":"T6_Mini-projets/05_Initiation_Pygame/#31-evenements-clavier","title":"3.1. \u00c9v\u00e8nements clavier","text":""},{"location":"T6_Mini-projets/05_Initiation_Pygame/#311-exemple-de-code","title":"3.1.1. Exemple de code","text":"La structure de code pour d\u00e9tecter l'appui sur une touche de clavier est, dans le cas de la d\u00e9tection de la touche \u00abFl\u00e8che droite\u00bb :
for event in pygame.event.get(): \n if event.type == KEYDOWN:\n if event.key == K_RIGHT:\n print(\"fl\u00e8che droite appuy\u00e9e\")\n
La touche (en anglais key) \u00abFl\u00e8che Droite\u00bb est appel\u00e9e K_RIGHT
par pygame
. Le nom de toutes les touches peut \u00eatre retrouv\u00e9 \u00e0 l'adresse https://www.pygame.org/docs/ref/key.html.
Remarque : c'est gr\u00e2ce \u00e0 la ligne initiale
from pygame.locals import *\n
que la variable K_RIGHT
(et toutes les autres) est reconnue."},{"location":"T6_Mini-projets/05_Initiation_Pygame/#312-probleme-de-la-remanence","title":"3.1.2. Probl\u00e8me de la r\u00e9manence","text":"Quand une touche de clavier est appuy\u00e9e, elle le reste un certain temps. Parfois volontairement (sur un intervalle long) quand l'utilisateur d\u00e9cide de la laisser appuy\u00e9e, mais aussi involontairement (sur un intervalle tr\u00e8s court), lors d'un appui \u00abclassique\u00bb. Il existe donc toujours un intervalle de temps pendant lequel la touche reste appuy\u00e9e. Que doit faire notre programme pendant ce temps ? Deux options sont possibles :
Par d\u00e9faut,pygame
est r\u00e9gl\u00e9 sur l'option 1. N\u00e9anmoins, il est classique pour les jeux vid\u00e9os de vouloir que \u00ablaisser la touche appuy\u00e9e\u00bb continue \u00e0 faire avancer le personnage. Nous allons donc faire en sorte que toutes les 50 millisecondes, un nouvel appui soit d\u00e9tect\u00e9 si la touche est rest\u00e9e enfonc\u00e9e. Cela se fera par l'expression :
pygame.key.set_repeat(50)\n
"},{"location":"T6_Mini-projets/05_Initiation_Pygame/#32-evenements-souris","title":"3.2 \u00c9v\u00e8nements souris","text":""},{"location":"T6_Mini-projets/05_Initiation_Pygame/#321-exemple-de-code","title":"3.2.1. Exemple de code","text":"La structure de code pour d\u00e9tecter l'appui sur un bouton de la souris est, dans le cas de la d\u00e9tection du bouton de gauche (le bouton 1) :
for event in pygame.event.get(): \n if event.type == MOUSEBUTTONDOWN and event.button == 1 :\n print(\"clic gauche d\u00e9tect\u00e9\")\n
"},{"location":"T6_Mini-projets/05_Initiation_Pygame/#322-recuperation-des-coordonnees-de-la-souris","title":"3.2.2. R\u00e9cup\u00e9ration des coordonn\u00e9es de la souris","text":"Le tuple (abscisse, ordonn\u00e9e)
des coordonn\u00e9es de la souris sera r\u00e9cup\u00e9r\u00e9 avec l'instruction pygame.mouse.get_pos()
.
Le d\u00e9placement d'un personnage se fera toujours par modification de ses coordonn\u00e9es (et visuellement, par effacement de la derni\u00e8re position). Ce d\u00e9placement pourra \u00eatre :
Pour afficher le personnage \u00e0 la position (100,200)
, on \u00e9crira :
position_perso.topleft = (100,200)\n
o\u00f9 position_perso
est l'objet de type rect
contenant les coordonn\u00e9es. Exercice 1
\u00c9nonc\u00e9Correction possibleR\u00e9aliser un d\u00e9placement al\u00e9atoire, comme l'animation ci-dessous.
Vous pourrez utiliser les instructions :
pygame.time.delay(1000)
afin de ne bouger le personnage que toutes les 1000 millisecondes.randint(a,b)
du package random
, qui renvoie un entier pseudo-al\u00e9atoire entre a
et b
.import pygame, sys\nfrom pygame.locals import *\nfrom random import randint\n\npygame.init()\n\nfenetre = pygame.display.set_mode((640, 480))\n\nperso = pygame.image.load(\"perso.png\").convert_alpha()\n\nposition_perso = perso.get_rect()\n\nwhile True :\n fenetre.fill([10,186,181])\n position_perso.topleft = (randint(0,540),randint(0,380))\n fenetre.blit(perso, position_perso)\n pygame.display.flip()\n pygame.time.delay(1000)\n
"},{"location":"T6_Mini-projets/05_Initiation_Pygame/#42-deplacement-relatif","title":"4.2. D\u00e9placement relatif","text":"Pour d\u00e9placer le personnage de 15 pixels vers la droite et de 10 pixels vers le haut par rapport \u00e0 sa position pr\u00e9c\u00e9dente, on \u00e9crira :
position_perso.move(15,-10)\n
o\u00f9 position_perso
est l'objet de type rect
contenant les coordonn\u00e9es. Exercice 2
\u00c9nonc\u00e9Correction possibleR\u00e9aliser un contr\u00f4le au clavier du personnage, comme dans l'animation ci-dessous.
import pygame, sys\nfrom pygame.locals import *\n\npygame.init()\npygame.key.set_repeat(50)\n\nfenetre = pygame.display.set_mode((640, 480))\n\nperso = pygame.image.load(\"perso.png\").convert_alpha()\n\nposition_perso = perso.get_rect()\n\npas_deplacement = 15 \n\nwhile True :\n\n for event in pygame.event.get() : \n if event.type == KEYDOWN:\n\n if event.key == K_DOWN : \n position_perso = position_perso.move(0,pas_deplacement)\n\n if event.key == K_UP :\n position_perso = position_perso.move(0,-pas_deplacement)\n\n if event.key == K_RIGHT : \n position_perso = position_perso.move(pas_deplacement,0)\n\n if event.key == K_LEFT : \n position_perso = position_perso.move(-pas_deplacement,0) \n\n # routine pour pouvoir fermer \u00abproprement\u00bb la fen\u00eatre Pygame\n if event.type == pygame.QUIT:\n pygame.display.quit()\n sys.exit()\n\n fenetre.fill([10,186,181])\n fenetre.blit(perso, position_perso)\n pygame.display.flip()\n
"},{"location":"T6_Mini-projets/05_Initiation_Pygame/#5-a-vous","title":"5. \u00c0 vous !","text":"Fabriquez le jeu que vous souhaitez \u00e0 partir des informations ci-dessus. Bien d'autres aides peuvent \u00eatre trouv\u00e9es dans les liens cit\u00e9es dans la partie Bibliographie.
Exemple de r\u00e9alisation possible : un clicker avec un temps qui diminue \u00e0 progressivement, et comptage des points.
Quelques aides :
\u00e9crire du texte :
font = pygame.font.Font(pygame.font.get_default_font(), 36)\ntext = font.render(\"Game Over\", True, (255, 0, 0))\nfenetre.blit(text, dest=(550,40))\n
dessiner un rectangle :
pygame.draw.rect(fenetre,(0,255,0),(500,20,100,10))\n
dessine un rectangle vert de 100 pixels sur 10 pixels, dont le coin en haut \u00e0 gauche est \u00e0 la position (500,20). g\u00e9rer le temps:
import time\ntopchrono = time.time()\ndelai = 5\nsortir = False\nwhile sortir == False :\n if time.time() - topchrono > delai :\n print(\"5 secondes se sont \u00e9coul\u00e9es\")\n sortir = True\n
Bibliographie
attention
L'activit\u00e9 ci-dessous n'est pas r\u00e9alisable sous Capytale, qui n'autorise pas l'utilisation du module requests
. Vous devez donc la r\u00e9aliser sur (par exemple) Thonny. Si vous n'avez pas (encore) Thonny sur votre ordinateur personnel, t\u00e9l\u00e9chargez-le ici
Par contre, les r\u00e9ponses aux questions pos\u00e9es doivent \u00eatre donn\u00e9es sur l'activit\u00e9 Capytale https://capytale2.ac-paris.fr/web/c/7371-1140429
Votre objectif est de trouver le mot de passe demand\u00e9 sur la page http://glassus1.free.fr/exoBF.html
Vous allez vous appuyer sur un leak (fuite) tr\u00e8s c\u00e9l\u00e8bre de mots de passe , qui est le leak du site Rockyou. Dans la base de donn\u00e9es de ce site, 32 millions de mots de passe \u00e9taient stock\u00e9s en clair.
Lorsque le site a \u00e9t\u00e9 pirat\u00e9 (par une injection SQL, voir le cours de Terminale), ces 32 millions de mots de passe se sont retrouv\u00e9s dans la nature. Ils sont aujourd'hui t\u00e9l\u00e9chargeables librement, et constituent un dictionnaire de 14 341 564 mots de passe diff\u00e9rents (car parmi les 32 millions d'utilisateurs, beaucoup utilisaient des mots de passe identiques).
Nous allons utiliser un fichier beaucoup plus l\u00e9ger ne contenant que les 1000 premiers mots de passe. Ce fichier est nomm\u00e9 extraitrockyou.txt
.
extraitrockyou.txt
","text":"T\u00e9l\u00e9chargez le fichier extraitrockyou.txt. Attention, ce fichier doit \u00eatre imp\u00e9rativement situ\u00e9 dans le m\u00eame r\u00e9pertoire que le fichier du code Python que vous allez \u00e9crire.
"},{"location":"T6_Mini-projets/Attaque_BF/#12-recuperer-les-elements-du-fichier","title":"1.2 R\u00e9cup\u00e9rer les \u00e9l\u00e9ments du fichier","text":"Ouvrir un nouveau code dans Thonny et enregistrez-le \u00e0 c\u00f4t\u00e9 du fichier extraitrockyou.txt
.
La ligne suivante va stocker dans une liste liste_mdp
les 1000 mots de passe pr\u00e9sents dans le fichier extraitrockyou.txt
.
liste_mdp = open(\"extraitrockyou.txt\").read().splitlines()\n
Si vous avez l'erreur :
FileNotFoundError: [Errno 2] No such file or directory: 'extraitrockyou.txt'\n
c'est que votre code et le fichier extraitrockyou.txt
ne sont pas dans le m\u00eame r\u00e9pertoire.
Question 1
\u00c9crire un code qui affiche les 1000 mots de passe contenus dans liste_mdp
.
(rappel : vous devez aller \u00e9crire vos r\u00e9ponses sur l'activit\u00e9 Capytale https://capytale2.ac-paris.fr/web/c/7371-1140429)
"},{"location":"T6_Mini-projets/Attaque_BF/#2-utilisation-du-module-requests","title":"2. Utilisation du modulerequests
","text":"Le module requests
de Python permet de r\u00e9cup\u00e9rer le contenu d'une page web dont on aura donn\u00e9 l'adresse en param\u00e8tre.
Souvenez-vous par exemple de cette superbe page : http://glassus1.free.fr/interesting.html
Exc\u00e9cutez le code ci-dessous :
import requests\np = requests.get(\"http://glassus1.free.fr/interesting.html\")\nprint(p.text)\n
Question 2
\u00c9crire ce qui s'affiche en console lors de l'ex\u00e9cution du code :
import requests\np = requests.get(\"http://glassus1.free.fr/interesting.html\")\nprint(p.text)\n
Si vous avez l'erreur :
ModuleNotFoundError: No module named 'requests'\n
c'est que le module requests
n'est pas install\u00e9. Dans Thonny, aller dans Outils / G\u00e9rer les paquets et installer requests
.
Un des 1000 mots de passe du fichier extraitrockyou.txt
est le bon. Mais comment savoir lequel ?
Question 3
Rendez-vous sur la page http://glassus1.free.fr/exoBF.html et proposer le mot de passe mauriac
. Quelle url s'affiche alors dans la barre d'adresse ?
Question 4
\u00c9crire un code qui va proposer le mot de passe vacances
et afficher le texte de la page obtenue.
Pour rappel la concat\u00e9nation des chaines de caract\u00e8res permet de faire ceci :
base = \"je vous souhaite de bonnes\"\nsuite = \"vacances\"\nphrase = base + suite\n
Question 5
\u00c9crire un code qui va afficher les 1000 urls diff\u00e9rentes qui serviront \u00e0 tester tous les mots de passe du fichier extraitrockyou.txt
.
Question 6
\u00c9crire un code qui d\u00e9termine le mot de passe de la page http://glassus1.free.fr/exoBF.html.
"},{"location":"T6_Mini-projets/D%C3%A9codeuses/","title":"D\u00e9codeuses du num\u00e9rique","text":"La BD en ligne est disponible ici.
Le pdf est disponible en t\u00e9l\u00e9chargement ici.
Les portraits sont accessibles ici.
Affectation des pr\u00e9sentations
Lors de sa descente vers la plan\u00e8te Mars le 18/02/2021, le rover Perseverance de la Nasa a frein\u00e9 sa chute gr\u00e2ce \u00e0 un parachute qui a intrigu\u00e9 quelques internautes du forum Reddit.
Vid\u00e9o du d\u00e9ploiement du parachute :
Les zones blanches et rouge se d\u00e9composent comme ceci :
"},{"location":"T6_Mini-projets/Exercice_Perseverance/#indications","title":"Indications","text":"Un grand bravo aux brillants redditors u/rdtwt1
et u/tend0g
.
https://sjwarner.github.io/perseverance-parachute-generator/?
"},{"location":"T6_Mini-projets/Exercice_Perseverance/#sources-attention-spoiler","title":"Sources (attention spoiler):","text":"Afin de travailler efficacement entre votre ordinateur personnel et votre VM du lyc\u00e9e, nous utiliser la solution GitHub.
"},{"location":"T6_Mini-projets/Github/#etape-0-creer-un-compte-github","title":"\u00c9tape 0 : cr\u00e9er un compte GitHub","text":"Cela se passe ici
"},{"location":"T6_Mini-projets/Github/#etape-1-creer-un-premier-depot-repository","title":"\u00c9tape 1 : cr\u00e9er un premier d\u00e9p\u00f4t (repository)","text":"Une fois termin\u00e9e la cr\u00e9ation de compte, GitHub vous proposera de cr\u00e9er votre premier d\u00e9p\u00f4t (on dira aussi repository, ou repo). Vous pourrez avoir autant de d\u00e9p\u00f4ts que vous voulez : \u00e0 chaque nouveau projet doit correspondre un nouveau d\u00e9p\u00f4t.
Cr\u00e9ez donc un d\u00e9p\u00f4t Projet Pygame
(ou comme vous voulez).
GitHub Desktop est un logiciel qui devra \u00eatre install\u00e9 sur nos VMs (c'est fait) mais aussi sur votre ordinateur personnel de travail. Vous trouverez les liens de t\u00e9l\u00e9chargement ici.
Le r\u00f4le de GitHub Desktop va \u00eatre de synchroniser vos fichiers locaux avec le serveur distant de github.com (\u00able cloud\u00bb). Contrairement \u00e0 une solution automatique (type Dropbox ou Google Drive), la synchronisation n'est pas automatique mais manuelle. C'est \u00e0 vous d'aller uploader vos fichiers (push) ou bien de les t\u00e9l\u00e9charger (fetch).
"},{"location":"T6_Mini-projets/Github/#etape-3-configurer-github-desktop","title":"\u00c9tape 3 : configurer GitHub Desktop","text":"Il va falloir pr\u00e9ciser \u00e0 GitHub que nous avons d\u00e9j\u00e0 un compte, et un d\u00e9p\u00f4t que nous avons cr\u00e9\u00e9 plus haut. Vous pouvez vous laisser guider ou suivre ce tutoriel
"},{"location":"T7_Divers/1_Conseils_generaux/cours/","title":"Conseils de travail","text":""},{"location":"T7_Divers/1_Conseils_generaux/cours/#conditions-materielles","title":"Conditions mat\u00e9rielles","text":"Il est conseill\u00e9 de travailler avec 3 espaces:
C'est en codant qu'on apprend \u00e0 coder
Tous les exemples de code dans le cours doivent \u00eatre retap\u00e9s (r\u00e9sistez \u00e0 l'envie du copier-coller) dans Thonny, soit en fen\u00eatre de script, soit en console.
Cela permet de :
et le plus important :
Thonny, comme la grande majorit\u00e9 des IDE Python, est compos\u00e9 de deux zones distinctes :
La zone de script est asynchrone. Il ne se passera rien tant que vous n'aurez pas ex\u00e9cut\u00e9 le script (par F5 par exemple). C'est donc l'endroit o\u00f9 on va r\u00e9diger son programme.
La console est synchrone : elle r\u00e9pond d\u00e8s que vous appuyez sur la touche Entr\u00e9e. Elle sert donc aux petits tests rapides, ou bien tests post-ex\u00e9cution d'un code.
Utilisation classique du couple script / console
Pour les extraits de code pr\u00e9sents sur ce site :
Exemple :
def accueil(n):\n for k in range(n):\n print(\"bonjour\") \n
>>>
est \u00e0 taper en console.Exemple :
>>> accueil(5)\n
"},{"location":"T7_Divers/1_Conseils_generaux/cours/#dossiers-fichiers-et-versionning","title":"Dossiers, fichiers et versionning","text":"Cette ann\u00e9e en NSI nous allons manipuler un certain nombre de fichiers. Il est important de les nommer et les classer de fa\u00e7on rigoureuse pour les retrouver rapidement et les partager.
Conseils
python1.py
, python2.py
, python3.py
, etc. Mais plut\u00f4t 1NSI_T4_tri_selection.py
par exemple pour un exercice de programmation sur le tri par selection au th\u00e8me 4.1NSI_projet_morpion_v1.py
, puis 1NSI_projet_morpion_v2.py
, 1NSI_projet_morpion_v3.py
, etc.Utiliser le clavier est souvent bien plus pratique et surtout plus rapide qu'utiliser la souris. Encore faut-il apprendre \u00e0 l'apprivoiser...
La s\u00e9lection au clavier
Outre les touches DEBUT
et FIN
qui permettent d'atteindre rapidement le d\u00e9but ou la fin d'une ligne, les fl\u00e8ches directionelles servent \u00e9videmment \u00e0 se d\u00e9placer dans du texte. Mais combin\u00e9es:
CTRL
: elles permettent de se d\u00e9placer de mot en mot;MAJ
: elles permettent de s\u00e9lectionner un caract\u00e8re;MAJ
et CTRL
: elles permettent de s\u00e9lectionner un mot.De m\u00eame, en se pla\u00e7ant en d\u00e9but d'une ligne et en combinant la touche MAJ
et FIN
, on s\u00e9lectionne la ligne enti\u00e8re.
Les raccourcis clavier
Il existe de tr\u00e8s nombreux raccourcis clavier qui permettent d'ex\u00e9cuter des t\u00e2ches courantes sans passer par les menus du logiciel. Certains sont (quasi-)universels, c'est-\u00e0-dire que ce sont les m\u00eames sur tous les logiciels, d'autres sont sp\u00e9cifiques \u00e0 chaque logiciel. Il est important d'en conna\u00eetre quelques-uns pour \u00eatre plus efficace.
Les universelsIDENavigateur WebCTRL+X
, CTRL+C
, CTRL+V
pour couper, copier, coller;CTRL+O
pour ouvrir un fichierCTRL+N
pour cr\u00e9er un nouveau document;CTRL+S
pour sauvegarder le document en cours;CTRL+MAJ+S
pour sauvegarder en pr\u00e9cisant le nom du fichier;CTRL+Z
pour annuler la derni\u00e8re action, CTRL+Y
ou CTRL+MAJ+Z
pour la r\u00e9tablir;CTRL+W
pour fermer un onglet;CTRL+Q
ou ALT+F4
pour fermer le logiciel;CTRL+A
pour s\u00e9lectionner tout (All).\u00c0 chercher de suite lorsqu'on utilise un nouvel IDE, les raccourcis pour les actions suivantes (entre parenth\u00e8ses ceux de Thonny):
F5
)CTRL+M
)CTRL+T
pour ouvrir un nouvel onglet;CTRL+H
pour ouvrir l'historique;CTRL
+ clic pour forcer l'ouverture d'un lien dans un nouvel onglet;MAJ
+ clic pour forcer l'ouverture d'un lien dans une nouvelle fen\u00eatre;Afin de pouvoir travailler sous le syst\u00e8me d'exploitation libre Linux sur les machines du lyc\u00e9e (sous Windows), nous utilisons la solution de virtualisation Proxmox. De mani\u00e8re simplifi\u00e9e :
Programmation
.Proxmox NSI
. Param\u00e8tres avanc\u00e9s
puis sur Continuer vers le site 172.17.191.244
Proxmox VE Login
, renseigner ses identifiants et s\u00e9lectionner Realm Proxmox VE authentication server
. ok
pour l'ignorer.Start
pour d\u00e9marrer la VM.Console
et choisir Spice
. telechargement.vv
apparu en bas \u00e0 gauche.Remplir ses identifiants dans la fen\u00eatre de connexion :
Basculer l'affichage en plein \u00e9cran
Comme pour tous les langages de programmation, il n'existe pas un logiciel permettant de coder en Python, mais un tr\u00e8s (tr\u00e8s) grand nombre de logiciels diff\u00e9rents, qu'on regroupe sous le nom d'IDE (interfaces de d\u00e9veloppement)
Pour la NSI, nous conseillons Thonny :
"},{"location":"T7_Divers/3_Thonny/cours/#installer-thonny","title":"Installer Thonny","text":"Rendez vous sur la page https://thonny.org/
T\u00e9l\u00e9chargez et installez la version qui correspond \u00e0 votre syst\u00e8me d'exploitation (Windows, Mac, Linux).
Pyzo, PyCharm, Spyder, VisualStudioCode... impossible de toutes les citer !
"},{"location":"T7_Divers/3_Thonny/cours/#solutions-en-ligne","title":"Solutions en ligne","text":"En ligne, sans aucune installation, vous pouvez utiliser https://console.basthon.fr/
ou bien m\u00eame la console ci-dessous !
>>>ou l'IDE qui suit :
\u25b6\ufe0f \u2935\ufe0f \u2934\ufe0f "},{"location":"T7_Divers/4_Processing/cours/","title":"Processing","text":"Processing est un outil de cr\u00e9ation multim\u00e9dia utilisant le code informatique. Simple de prise en main, il a \u00e9t\u00e9 cr\u00e9\u00e9 par des artistes pour des artistes. On peut utiliser le langage Python pour entrer les instructions.
Nous l'utiliserons pour ajouter du graphisme \u00e0 nos cr\u00e9ations...
Documentation"},{"location":"T7_Divers/4_Processing/cours/#les-bases-de-processing","title":"Les bases de Processing","text":""},{"location":"T7_Divers/4_Processing/cours/#repere","title":"Rep\u00e8re","text":"
\u00c0 l'ex\u00e9cution de tout script Processing, une fen\u00eatre s'affiche avec une zone de dessin. Sa taille se d\u00e9finit \u00e0 l'aide de la fonction size
. Par exemple, pour cr\u00e9er une zone de dessin de 300 pixels sur 200 pixels, on utilisera:
size(300, 200)\n
Chaque pixel de cette zone est rep\u00e9r\u00e9e par des coordonn\u00e9es dans le rep\u00e8re suivant, dont l'origine se situe en haut \u00e0 gauche et l'axe des ordonn\u00e9es est orient\u00e9 vers le bas.
"},{"location":"T7_Divers/4_Processing/cours/#traces","title":"Trac\u00e9s","text":"
Trac\u00e9s de base
point
: permet de dessiner un point (pixel). En param\u00e8tre, les coordonn\u00e9es du point.line
: permet de tracer une ligne entre deux points. En param\u00e8tres, les coordonn\u00e9es des deux points.rect
: permet de tracer un rectangle. En param\u00e8tres, les coordonn\u00e9es du sommet haut-gauche, puis la largeur et la hauteur du rectangle.ellipse
: permet de tracer une ellipse. En param\u00e8tres, les coordonn\u00e9es du centre, puis la largeur et la hauteur (mettre la m\u00eame valeur pour un cercle).Copier-coller le code suivant et faire varier les param\u00e8tres pour bien les comprendre.
size(200, 200)\npoint(10, 60)\nline(10, 10, 100, 150)\nrect(80, 10, 20, 50)\nellipse(150, 100, 80, 40)\n
"},{"location":"T7_Divers/4_Processing/cours/#couleurs","title":"Couleurs","text":"Pinceau
background
: permet de d\u00e9finir la couleur du fond de la zone de dessin. En param\u00e8tres, les trois composantes RGB de la couleur.stroke
: permet de d\u00e9finir la couleur du pinceau (noir par d\u00e9faut) pour le contour de la forme. En param\u00e8tres, les trois composantes RGB de la couleur.noStroke
: permet de dessiner une forme sans coutour (pas de param\u00e8tre).strokeWeight
: permet de d\u00e9finir la largeur du pinceau. En param\u00e8tre, le nombre de pixel.fill
: permet de d\u00e9finir la couleur de remplissage de la forme. En param\u00e8tres, les trois composantes RGB de la couleur.Copier-coller le code suivant et faire varier les param\u00e8tres pour bien les comprendre.
size(200, 200)\nbackground(255, 255, 255)\nstroke(255, 0, 0)\npoint(10, 60)\nline(10, 10, 100, 150)\nstroke(0, 127, 255)\nstrokeWeight(5)\nrect(80, 10, 20, 50)\nnoStroke()\nfill(204, 153, 204)\nellipse(150, 100, 80, 40)\n
"},{"location":"T7_Divers/4_Processing/cours/#exercices","title":"Exercices","text":"Exercice 2
\u00c9crire un programme qui affiche le drapeau fran\u00e7ais, comme ci-contre, dans une zone de 300 x 200 pixels.
Exercice 3
\u00c9crire un programme qui trace un quadrillage (espacement de 20 pixels).
Contrainte: en seulement 3 lignes (sans compter \u00e9ventuellement size
.
Exercice 4
Afficher une croix verte de longueur 50 centr\u00e9e au point (60 ; 40), et un cercle rouge de diam\u00e8tre 30 centr\u00e9 en (150 ; 100). On prendra 10 pixels comme \u00e9paisseur.
Exercice 5
Cr\u00e9ez un programme permettant d\u2019afficher 100 disques \u00e0 l\u2019\u00e9cran. La taille de chaque disque devra \u00eatre al\u00e9atoire (mais comprise entre 20 et 50). La couleur de chaque disque devra aussi \u00eatre al\u00e9atoire.
Avec Processing, il est tr\u00e8s simple d\u2019avoir un nombre al\u00e9atoire : random(a,b)
permet d\u2019obtenir un nombre al\u00e9atoire entre a
et b
.
Pour r\u00e9aliser facilement de jolis graphiques, nous utilisons sur les ordinateurs du lyc\u00e9e le logiciel Processing. Celui-ci permet d'\u00e9crire du code Python et d'avoir un rendu imm\u00e9diat dans une fen\u00eatre s\u00e9par\u00e9e.
Pour le travail \u00e0 la maison, nous utilisons le service Capytale.
Probl\u00e8me, il n'est pas possible d'\u00e9crire du code Processing dans Capytale.
"},{"location":"T7_Divers/4_Processing_p5/cours/#2-une-solution-la-librairie-p5","title":"2. Une solution : la librairie p5","text":"Si Processing n'existe pas dans Capytale, une solution tr\u00e8s similaire est disponible : la librairie p5.
Remarque
La librairie p5
incluse dans Capytale est l\u00e9g\u00e8rement diff\u00e9rente de la libraire p5
utilisable dans Thonny (ou tout autre IDE). En effet, pour pouvoir fonctionner sur Capytale, elle a \u00e9t\u00e9 en partie r\u00e9-\u00e9crite par un des d\u00e9veloppeurs de Capytale, Romain Casati.
Les codes Processing que nous avons \u00e9crits jusqu'\u00e0 pr\u00e9sent sont des codes statiques. Mais l'architecture naturelle d'un code Processing ou p5 est en r\u00e9alit\u00e9 articul\u00e9e autour de deux fonctions : la fonction setup()
et la fonction draw()
.
setup()
","text":"Comme son nom l'indique, elle va proc\u00e9der \u00e0 tous les r\u00e9glages initiaux avant de commencer le dessin : taille de la fen\u00eatre, (\u00e9ventuellement couleur d'arri\u00e8re-plan), autres r\u00e9glages.
Elle n'est ex\u00e9cut\u00e9e qu'une seule fois.
"},{"location":"T7_Divers/4_Processing_p5/cours/#32-la-fonction-draw","title":"3.2 La fonctiondraw()
","text":"C'est dans cette fonction que toutes les instructions de dessin seront donn\u00e9es.
Tr\u00e8s important : cette fonction est une boucle infinie. Elle est donc r\u00e9p\u00e9t\u00e9e (\u00e0 une certaine cadence qui est r\u00e9glable) jusqu'\u00e0 ce que (par exemple) l'utilisateur ferme la fen\u00eatre.
Des instructions \u00e9crites dans la fonction setup()
peuvent influer sur cette boucle infinie draw()
: notamment l'instruction noLoop()
qui permet de n'ex\u00e9cuter la fonction draw()
qu'une seule fois.
run()
","text":"Un code p5 devra forc\u00e9ment se terminer par l'instruction run()
createCanvas()
vs size()
","text":"Pour cr\u00e9er une zone de dessin de 300 pixels sur 300 pixels :
size(300,300)
createCanvas(300,300)
Nos premiers codes en Processing actuellement sont statiques : ils n'ont pas d'animation. Processing accepte alors que le code ne comporte ni fonction setup()
ni fonction draw()
.
Par contre, pour faire un code statique en p5, il faudra quand m\u00eame que les fonctions setup()
etdraw()
soient pr\u00e9sentes. On indiquera l'instruction noLoop()
dans le setup()
pour que le draw()
ne soit execut\u00e9 qu'une fois.
Exemple de passage d'un code statique en Processing \u00e0 un code statique en p5 :
Vous pouvez aussi comparer des codes statiques Processing avec leur \u00e9quivalent en p5 dans la feuille d'exercices sur Processing.
"},{"location":"T7_Divers/5_Capytale/cours/","title":"Utilisation du service Capytale","text":"Capytale est accessible via Lyc\u00e9econnect\u00e9, il faut donc avoir ses identifiants Educonnect.
"},{"location":"T7_Divers/5_Capytale/cours/#activite-test","title":"Activit\u00e9-test :","text":"Go !
.Exercice 1
\u00c9nonc\u00e9Correctionp
et de q
soient \u00e9chang\u00e9es :>>> p = 3\n>>> q = 7\n>>>\n>>>\n>>>\n
2. Proposer une autre m\u00e9thode plus rapide \u00e0 \u00e9crire : >>> p = 3\n>>> q = 7\n>>>\n
>>> p = 3\n>>> q = 7\n>>> temp = p\n>>> p = q\n>>> q = temp\n
2.
>>> p = 3\n>>> q = 7\n>>> p, q = q, p\n
Exercice 2
\u00c9nonc\u00e9Correctionscore
soit augment\u00e9e de 20: >>> score = 0\n>>> \n
>>> score = 0\n>>> \n
1.
>>> score = 0\n>>> score = score + 20\n
2. >>> score = 0\n>>> score += 20\n
Exercice 3
\u00c9nonc\u00e9CorrectionJe souhaite coder un jeu. Je vais stocker dans une variable la largeur de l'\u00e9cran (qui vaudra 640 pixels par d\u00e9faut) et dans une autre variable la hauteur de l'\u00e9cran (qui vaudra 400 pixels par d\u00e9faut).
\u00c9crire ce que peuvent \u00eatre les deux premi\u00e8res lignes de mon code :
1 \n2 \n
largeur_ecran = 640\nhauteur_ecran = 400\n
Exercice 4
\u00c9nonc\u00e9CorrectionOn consid\u00e8re le programme suivant :
for lettre in \"LUNDI\":\n print(lettre)\n
\u00c9crire ci-dessous ce qui s'affiche en console lors de l'ex\u00e9cution de ce programme. \n
L\nU\nN\nD\nI\n
Exercice 5
\u00c9nonc\u00e9CorrectionOn consid\u00e8re le programme suivant :
liste_langages = ['Python', 'C++', 'SmallTalk']\nfor langage in liste_langages:\n print(langage, \"est un langage orient\u00e9-objet\")\n
\u00c9crire ci-dessous ce qui s'affiche en console lors de l'ex\u00e9cution de ce programme.
\n
Python est un langage orient\u00e9-objet\nC++ est un langage orient\u00e9-objet\nSmallTalk est un langage orient\u00e9-objet\n
Exercice 6
\u00c9nonc\u00e9CorrectionProposer un code pour \u00e9crire (intelligemment) les lignes suivantes :
Voici le verdict du Choixpeau Magique :\nHarry sera \u00e0 Griffondor\nHermione sera \u00e0 Griffondor\nRon sera \u00e0 Griffondor\n
\n
print('Voici le verdict du Choixpeau Magique :')\npersonnages = ['Harry', 'Hermione', 'Ron']\nfor nom in personnages:\n print(nom, 'sera \u00e0 Griffondor')\n
"},{"location":"T8_DS/DS03/","title":"DS03","text":"correction sur Capytale.
"},{"location":"T8_Liens_utiles/liens/","title":"Liens utiles","text":""},{"location":"T8_Liens_utiles/liens/#a-propos-de-la-specialite-nsi","title":"\u00c0 propos de la sp\u00e9cialit\u00e9 NSI","text":"Quelques sites de challenges/\u00e9nigmes/d\u00e9fis de programmation:
Interstices
Inria
Au cas o\u00f9 vous vous ennuieriez...