Python list-tuple-dict

Identification

Infoforall

5 - Types construits


Nous avons vu les types de données et le moyen de les stocker dans des variables.

Reste un problème : si vous avez besoin de stocker 100 données, il va vous falloir 100 variables...

Nous allons voir comment créer des sortes de variables-conteneurs à données : nous pourront ainsi stocker 100 données dans une seule variable. C'est mieux !

Type construit comme un meuble à tiroirs
Un type construit, une sorte de meuble à tiroirs

Vous allez voir par exemple comment stocker les notes de 30 élèves d'une classe et comment récupérer facilement la note de l'élève numéro 12 : il a eu 2 :

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 >>> notes = [2, 13, 18, 13, 0, 18, 1, 4, 10, 13, 12, 17, 2, 20, 15, 16, 10, 6, 16, 18, 19, 17, 4, 6, 15, 18, 3, 12, 1, 6] >>> notes[12] 2

Vous allez aussi comprendre qu'en informatique on commence à compter à partir de 0 et pas à partir de 1 (voir ci-dessus...).

Evaluation

  question -

  questions 06-08-13

Exercices supplémentaires 🏠 : Exercices

Documents de cours PDF : .PDF

Sources latex : .TEX et entete.tex et licence.tex

Résumé : Version HTML ou fond blanc ou ou PDF (couleur ou gris)

1 - Principe général

1.1 Type simple : principe

Le type simple fait référence à un contenu unique.

On peut voir une variable de ce type comme une liaison entre un NOM et un CONTENU en mémoire :

une sorte de boite une sorte de liaison
flowchart LR D([Variable]) --> A([Contenu])
1.2 Type construit : principe

Le type construit fait plutôt référence à une armoire qui contient plusieurs boites. Ici, un tableau t1 qui fait référence à 10, 100 et 1000 :

une sorte d'armoire

Il est néanmoins préférable d'y voir un NOM qui permet d'atteindre un ensemble de CONTENUS.

une sorte de liaison plus complexe

Ici, c'est un numéro qui permet de distinguer les contenus qu'on peut trouver dans le conteneur pointé par la variable de nom t1.

flowchart LR D([Variable]) --> M([Conteneur]) M -- étiquette A --> A([Contenu A]) M -- étiquette B --> B([Contenu B]) M -- étiquette C --> C([Contenu C])

2 - String

Les types construits permettent de stocker n'importe quel autre type de données.

Le string est donc un cas particulier : il permet de stocker uniquement des caractères.

Rappels

(Rappel) 2.1 STRING : définition

Le type gérant les textes se nomme string. C'est un conteneur formant une collection ordonnée de caractères.

String est un mot anglais qui signifie "chaîne" en français ; un texte est une chaîne de caractères qui se suivent. Exemple avec le mot Bonjour :

Indice 0 1 2 3 4 5 6
Elément 'B' 'o' 'n' 'j' 'o' 'u' 'r'

Indice se traduit par index en anglais.

flowchart LR D([Variable]) --> M([conteneur-string]) M -- indice 0 --> A([caractère 0]) M -- indice 1 --> B([caractère 1]) M -- indice 2 --> C([caractère 2])

Notez bien que la première case est la case d'indice 0, pas celle d'indice 1. Les indices disponibles dans un string de 7 caractères vont donc de 0 à 6.

(Rappel) 2.2 STRING : déclaration avec Python

Type str

En Python, les strings sont gérés par le type nommé str.

Déclaration (avec des guillemets)

Un string Python est délimité par deux délimitateirs signalant son début et sa fin.

  • soit un guillemet simple : 'Bonjour' (touche du 4)
  • soit un guillemet double : "Bonjour" (touche du 3)
  • soit trois guillemets simples : '''Bonjour'''
  • soit trois guillemets doubles : """Bonjour"""
  • mais jamais de mélange pour un même string : si on mélange sur un même string, Python perd le fil : c'est une erreur de syntaxe.
  • >>> "Hello World !' File "<pyshell>", line 1 "Hello World !' ^ SyntaxError: EOL while scanning string literal

    La phrase d'erreur peut se traduire par "Je suis arrivé à la fin de la ligne sans rencontrer le caractère de fermeture pendant que j'étais en train de lire le string".

Exemples
  • Un guillemet simple pour l'ouverture et la fermeture.
  • >>> 'Hello World !' 'Hello World !' >>> type('Hello World !') <class 'str'>
  • Un guillemet double pour l'ouverture et la fermeture.
  • >>> "Hello World !" 'Hello World !' >>> type("Hello World !") <class 'str'>

    Python répond toujours avec des guillemets simples lorsqu'il le peut.

Déclaration d'un string multi-ligne

On peut déclarer un string intégrant des passages à la ligne (celles intégrant des appuis sur ENTREE) en utilisant 3 guillemets :

1 2 3 4 5 6 7 8
s = """Voici une liste : - premier truc - deuxième truc - troisième truc En ici, c'est fini""" print(s)

Voici l'affichage obtenu dans la console :

Voici une liste : - premier truc - deuxième truc - troisième truc En ici, c'est fini
Déclaration d'un string vide

Deux solutions

>>> s = "" >>> s '' >>> s = str() >>> s ''
Guillemet simple ou apostrophe ?

Dans certaines polices de caractères, il n'y a pas de différence visuelle mais il existe plusieurs apostrophes différentes, dont l'apostrophe droite : guillemet simple simple.

' ’ ʾ ′ ˊ ˈ ꞌ ‘ ʿ ‵ ˋ

Mais attention, Python nécessite bien la présence de guillemet simple, et pas d'une apostrophe (le trait est légérement courbé normalement). C'est d'ailleurs pour cela qu'il ne faut pas écrire de code à l'aide d'un traitement de texte : il utilise le plus souvent une apostrophe (courbée) lorsqu'on tape sur la touche 4.

(Rappel) 2.3 STRING : opérateurs Python

Même syntaxe, sémantique différente

On retrouve une partie des symboles d'opérateurs applicables aux valeurs numériques mais la signification (ou sémantique) ne va pas être la même.


CONCATÉNATION avec +

str + str -> str

>>> "bon" + "jour" 'bonjour'
>>> '5' + '5' '55'

La concaténation correspond à une juxtaposition. D'où l'utilisation d'un autre terme qu'addition.

Le deuxième exemple peut être perturbant pour un humain ! Mais il suffit de le lire correctement pour comprendre la réponse '55' que fournit l'interpréteur : Que donne la concaténation du caractère '5' et du caractère '5' ?

Il n'existe pas de signature liée à des entrées de type str + int ou int + str. C'est normal, quel sens pourrait-on donner à cette opération ?

>>> 'Bonj' + 5 TypeError: can only concatenate str (not "int") to str

Concaténation (str) : coût LINÉAIRE par rapport au nombre n de caractères.


RÉPÉTITION avec *

str * int -> str

int * str -> str

La répétition correspond à une sorte de copier-coller d'un string.

>>> "Bon" * 2 'BonBon' >>> 4 * "Pom ! " 'Pom ! Pom ! Pom ! Pom ! ' >>> '#' * 20 '####################'

Il n'existe pas de signature liée à des entrées de type str * float ou float * str.

Répétition (str) : coût LINÉAIRE par rapport au nombre n de caractères.


Et les autres ?

Les autres opérateurs (- / // % **">) ne sont pas implémentés sur les strings. Leur utilisation sur un string provoque donc une erreur.

(Rappel) 2.4 STRING : déterminer sa longueur

La longueur d'un string correspond au nombre de "cases-caractères" du string.

Cette longueur est importante pour ne pas déborder hors du string lors d'une lecture par indice : si le string est de longueur 45, vous savez que les indices valides vont de 0 à 44.

On utilise la fonction native len().

Indice 0123456 >>> mot = "Bonjour" >>> len(mot) 7

Comme on voit qu'il y a 7 caractères, on sait alors qu'on peut demander des indices allant de 0 à ...6.

Longueur (str) : coût CONSTANT par rapport au nombre n de caractères (on stocke cette valeur dans l'objet)

Nouveautés

2.5 STRING : accéder à une case avec [i]

Accés (avec les crochets)

On peut accéder au caractère stocké dans une case dont on connaît l'indice en tapant le nom de la variable-string suivie de crochets et de l'indice.

Indice 0123456 >>> mot = "Bonjour" >>> mot[0] 'B' >>> mot[1] 'o' >>> mot[2] 'n' >>> mot[7] IndexError: list index out of range

Accès (str) : coût CONSTANT par rapport au nombre n de caractères.

Trois choses à distinguer
  • Le conteneur s (le string)
  • Les indices i
  • Les contenus s[i]
2.6 STRING : immuable en Python (pas de modification)

En Python, les strings sont immuables (ou non mutables en franglais) : on ne peut pas modifier le contenu d'une case après la création du string.

>>> a = "bonjour" >>> a[0] = "d" TypeError: 'str' object does not support item assignment

D'autres langages se comportent comme Python : Java, C#, JavaScript...

2.7 STRING : parcours par indices

On utilise une boucle for i in range(len(s)).

Ainsi avec "bonjour", on a 7 caractères d'indices 0 à 6.

1 2 3 4
s = "bonjour" for i in range(len(s)): # Pour chaque indice possible dans s print(s[i]) # Affiche le contenu de la case i

Ce programme est équivalent à ceci :

1 2 3 4 5 6 7 8 9
s = "bonjour" print(s[0]) print(s[1]) print(s[2]) print(s[3]) print(s[4]) print(s[5]) print(s[6])

Ils affichent l'un et l'autre ceci dans la console :

b o n j o u r

Accès à tous les caractères (str) : coût LINÉAIRE par rapport au nombre n de caractères.

2.8 STRING : mot-clés in et not in

Test d'appartenance ou de présence

On utilise l'opérateur binaire in qui renvoie un booléen.

Pour savoir si le string contenu est présent dans le string s, on tape contenu in s.

>>> "bon" in "bonjour" True >>> "Bon" in "bonjour" False

Traduction : "bon" est-il présent dans "bonjour" ? "Bon" est-il présent dans "Bonjour" ?

Appartenance (str) : coût LINÉAIRE par rapport au nombre n de caractères.

Test de non-appartenance ou d'absence

On utilise l'opérateur binaire not in qui renvoie un booléen.

Pour savoir si le string contenu n'est pas présent dans le string s, on tape contenu not in s.

>>> "bon" not in "bonjour" False >>> "Bon" not in "bonjour" True

Traduction : "bon" est-il absent de "bonjour" ? "Bon" est-il absent de "Bonjour" ?

⚙ 01° Réaliser un programme qui stocke dans deux variables nb1 et nb2 le nombre de caractères présents dans les deux paragraphes fournis ci-dessous.

Paragraphe 1

En informatique, un système d'exploitation (souvent appelé OS — de l'anglais operating system — ou parfois SE — en français) est un ensemble de programmes qui dirige l'utilisation des ressources d'un ordinateur par les autres programmes et applications.

Paragraphe 2

Linux ou GNU/Linux est une famille de systèmes d'exploitation open source de type Unix fondés sur le noyau Linux créé en 1991 par Linus Torvalds. De nombreuses distributions Linux ont depuis vu le jour et constituent un important vecteur de popularisation du mouvement du logiciel libre.

...CORRECTION...

Programme qui mémorise

1 2 3 4 5
p1 = "En informatique, un système d'exploitation (souvent appelé OS — de l'anglais operating system — ou parfois SE — en français) est un ensemble de programmes qui dirige l'utilisation des ressources d'un ordinateur par les autres programmes et applications." p2 = "Linux ou GNU/Linux est une famille de systèmes d'exploitation open source de type Unix fondés sur le noyau Linux créé en 1991 par Linus Torvalds. De nombreuses distributions Linux ont depuis vu le jour et constituent un important vecteur de popularisation du mouvement du logiciel libre." nb1 = len(p1) nb2 = len(p2)

⚙ 02° Réaliser un programme qui affiche le 27e caractère de chacune des phrases suivantes (attention, il s'agit donc du caractère d'indice... 26) :

Phrase 1

On notera que l'indice du premier élément ne porte pas le numéro 1 mais bien le numéro 0 !

Phrase 2

On notera également qu'on peut avoir accès à l'élément 5 sans avoir lu au préalable le 2,3 et 4. Ce n'est pas le cas pour toutes les structures de données.

...CORRECTION...

1 2 3 4 5
phrase1 = "On notera que l'indice du premier élément ne porte pas le numéro 1 mais bien le numéro 0 !" phrase2 = "On notera également qu'on peut avoir accès à l'élément 5 sans avoir lu au préalable le 2,3 et 4. Ce n'est pas le cas pour toutes les structures de données." print(phrase1[26]) print(phrase2[26])

⚙ 03° Rajouter des commentaires avec # (sur chaque ligne n'en comportant pas) de façon à expliquer ce que réalise ce programme. Attention, il faut expliquer l'intention de chaque ligne, pas de traduction mot à mot qui n'apporterait rien.

1 2 3 4 5 6 7 8 9 10 11
txt = "On notera que l'indice du premier élément ne porte pas le numéro 1 mais bien le numéro 0 !" nbr_e = 0 # Initialisation à 0 du compteur des e for i in range( len(txt) ): caractere = txt[i] print(caractere) if caractere == 'e': nbr_e = nbr_e + 1 print("Nombre de e :") print(nbr_e)

...CORRECTION...

1 2 3 4 5 6 7 8 9 10 11
txt = "On notera que l'indice du premier élément ne porte pas le numéro 1 mais bien le numéro 0 !" nbr_e = 0 # Initialisation à 0 du compteur des e for i in range( len(txt) ): # pour chaque indice possible dans txt caractere = txt[i] # on récupère le caractère en position i print(caractere) # on affiche ce caractère if caractere == 'e': # si ce caractère est un e nbr_e = nbr_e + 1 # on incrémente le compteur print("Nombre de e :") # on affiche ce string print(nbr_e) # on affiche le compteur

⚙ 04° Rajouter des commentaires de façon à expliquer ce que réalise ce programme. Attention, il faut expliquer l'intention de chaque ligne, pas de traduction mot à mot qui n'apporterait rien.

...AIDE...

Si on analyse le programme fourni, on voit :

  • Une déclaration de fonction est_binaire() en ligne 1. On voit que lors de l'appel à cette fonction, il faudra lui envoyer quelque chose qu'elle placera dans une variable nommée s.
  • Un appel à est_binaire() en ligne 7. Cette ligne n'est là que pour vous proposez un exemple : vous pouvez modifier l'appel et lui demander de travailler sur autre chose.

Vous devez donc travailler en considérant que vous ne savez pas ce que contient exactement s mais qu'il s'agit bien d'un string et qu'il faut vérifier s'il peut s'agir d'un string représentant un contenu binaire, c'est à dire comportant uniquement des 0 et des 1.

1 2 3 4 5 6 7
def est_binaire(s): for i in range(len(s)): if s[i] not in "01": return False return True reponse = est_binaire("011101200")

...CORRECTION...

1 2 3 4 5 6 7
def est_binaire(s): # déclaration d'une fonction est_binaire() for i in range(len(s)): # pour chaque indice possible dans le string s if s[i] not in "01": # si le caractère en position i n'est ni "0" ni "0" return False # on sort immédiatement en répondant False return True # après la boucle, on répond True si on arrive ici reponse = est_binaire("011101200") # on lance un appel en envoyant "011101200" dans s puis on stocke le résultat dans reponse

3 - Tableau statique

Imaginons qu'on veuille stocker des notes d'élèves sur un DS. Prenons une classe de 4 élèves pour l'exemple (un exemple très réaliste...) 

Nous pourrions stocker les notes d'Alice, Bob, Charlie et Dolores de cette façon :

1 2 3 4
alice = 20 bob = 8 charlie = 18 dolores = 12

Mais avec une trentaine d'élèves par classe, ça devient vite lassant...

3.1 TABLEAU STATIQUE : définition

Un tableau statique est un tableau comportant un nombre de cases fixé à la création.

Un tableau est un conteneur formant une collection ordonnée d'éléments ayant tous le même type. On peut donc avoir un tableau statique d'integers, ou un tableau statique de floats par exemple.

Les cases sont identifiées par un numéro nommé indice (index en anglais).

Voici deux exemples de tableaux :

Un tableau de caractères de 3 cases (indices 0-1-2) 

Indice 0 1 2
Elément 'A' 'B' 'C'

Un tableau de flottants de 4 cases (indices 0-1-2-3) :

Indice 0 1 2 3
Elément 5.89 12.56 15.89 5.0
flowchart LR D([Variable]) --> M([conteneur-tableau]) M -- indice 0 --> A([élément 0]) M -- indice 1 --> B([élément 1]) M -- indice 2 --> C([élément 2])

Notez bien que la première case est la case d'indice 0, pas celle d'indice 1. Si un tableau possède 20 cases, les indices disponibles vont de 0 à 19.

3.2 TABLEAU STATIQUE : déclaration avec Python

Les tableaux statiques sont implémentés en Python sous forme d'une structure de données dont le type se nomme list.

A - Déclaration par extension

On peut enregistrer une séquence de données dans un tableau statique en utilisant la syntaxe suivante :

  • un crochet [ en ouverture,
  • un crochet ] en fermeture et
  • des virgules pour séparer les valeurs.

Exemple avec un tableau contenant les notes de quatre élèves :

>>> notes = [20, 8, 18, 12] >>> type(notes) <class 'list'>

On notera que le type list de Python n'est pas un vrai tableau STATIQUE. Il permet de faire beaucoup plus de chosesE :

  • les cases peuvent contenir des données de types différents,
  • on peut créer ou supprimer des cases : c'est un tableau DYNAMIQUE.

Aujourd'hui nous n'utiliserons que l'aspect tableau STATIQUE.

.
B - Déclaration d'un grand tableau

On peut déclarer un tableau sur plusieurs lignes en tapant sur ENTREE après chaque virgule. Exemple :

1 2 3 4 5 6 7
eleves = ["Lisa", "Scott", "Matthias", "Antoine", "Ethan", "Lucas", "Manon"]

Cela prend plus de lignes mais on comprend un peu mieux ce qu'on place où.

C - Déclaration d'un tableau vide

Deux solutions

>>> t = [] >>> t [] >>> t = list() >>> t [] >>> bool(t) # t est ici [] donc vide False
3.3 TABLEAU STATIQUE : opérateurs Python


CONCATÉNATION avec +

list + list -> list

>>> [10, 20] + [5, 30] [10, 20, 5, 30]

Concaténation (list) : coût LINÉAIRE par rapport au nombre n d'éléments au total.


RÉPÉTITION avec *

list * int -> list

int * list -> list

>>> [10] * 3 [10, 10, 10] >>> 3 * [12] [12, 12, 12]

Répétition (list) : coût LINÉAIRE par rapport au nombre n d'éléments au total.

3.4 TABLEAU STATIQUE : accéder à une case avec [i]

Accès (avec des crochets)

On peut accéder à l'élément stocké dans une case dont on connait l'indice en tapant simplement le nom de la variable-tableau suivie de crochets et du numéro d'indice.

Indice 0 1 2 3 >>> notes = [20, 8, 18, 12] >>> notes[0] 20 >>> notes[1] 8 >>> notes[2] 18 >>> notes[3] 12 >>> notes[4] IndexError: list index out of range

Accès en lecture (list) : coût CONSTANT par rapport au nombre n d'éléments.

Trois choses à distinguer
  • Le conteneur t (le tableau)
  • Les indices i
  • Les contenus t[i]
3.5 TABLEAU STATIQUE : déterminer sa longueur

La longueur d'un tableau correspond au nombre de "cases-éléments" du tableau.

On utilise la fonction native len().

Indice 0 1 2 3 >>> notes = [20, 8, 18, 12] >>> len(notes) 4

Comme on voit qu'il y a 4 notes, on sait alors qu'on peut demander des indices allant de 0 à ...3.

Pour le type list : coût CONSTANT par rapport au nombre n d'éléments : le nombre d'éléments est mémorisé, il suffit de lire sa valeur.

Avec un tableau plus basique, le coût est LINÉAIRE puisqu'il faut partir du début et compter les cases une par une jusqu'à la fin.

3.6 TABLEAU STATIQUE : muable en Python (modification possible)

En Python, les tableaux sont muables (ou mutables en anglais) : on peut modifier le contenu d'une case après la création du tableau.

Imaginons qu'on ai oublié des points à Bob (l'élève d'indice 1) : il n'a pas 8 mais 11 finalement. Voici comment nous pourrions modifier le tableau APRES création

Indice 0 1 2 3 >>> notes = [20, 8, 18, 12] >>> notes[1] = 11 >>> notes [20, 11, 18, 12]

Ce n'est pas une affectation sur le tableau lui-même : l'affectation est faite sur l'une des cases notes[i] du tableau.

Accès en modification (list) : coût CONSTANT par rapport au nombre n d'éléments.

3.7 TABLEAU STATIQUE : parcours par indices

On utilise une boucle for i in range(len(t)).

Ainsi avec [20, 8, 18, 12], on a 4 notes d'indices 0 à 3.

1 2 3 4
t = [20, 8, 18, 12] for i in range(len(t)): # Pour chaque indice possible dans t print(t[i]) # Affiche le contenu de la case i

Ce programme est équivalent à ceci :

1 2 3 4 5 6
t = [20, 8, 18, 12] print(t[0]) print(t[1]) print(t[2]) print(t[3])

Ils affichent l'un et l'autre ceci dans la console :

20 8 18 12

Le coût de la lecture de toutes les cases est LINÉAIRE par rapport au nombre n d'éléments.

Pourquoi ? On remarquera que dans le premier programme :

  1. Le calcul de la longueur L3 est à coût constant
  2. La ligne 4 est à coût constant
  3. Le boucle L3-L4 est réalisée n fois (autant que de cases).

On réalise donc n fois des actions à coût constant : c'est donc LINÉAIRE.

3.8 TABLEAU STATIQUE : mot-clés in et not in

Test d'appartenance ou de présence

On utilise l'opérateur binaire in qui renvoie un booléen.

Pour savoir si le contenu est présent dans le tableau t, on tape contenu in t.

>>> "Alice" in ["Alice", "Bob", "Charlie"] True >>> "Dana" in ["Alice", "Bob", "Charlie"] False

Traduction : "Alice" est-elle présente dans la liste des élèves ? "Dana" est-elle présente dans la liste ?

Appartenance (list) : coût LINÉAIRE par rapport au nombre n d'éléments.

Test de non-appartenance ou d'absence

On utilise l'opérateur binaire not in qui renvoie un booléen.

Pour savoir si le contenu n'est pas présent dans le tableau t, on tape contenu not in t.

>>> "Alice" not in ["Alice", "Bob", "Charlie"] False >>> "Dana" not in ["Alice", "Bob", "Charlie"] True

Traduction : "Alice" est-elle absente de la liste des élèves ? "Dana" est-elle absente de la liste ?

Notez qu'on peut demander cela avec deux syntaxes différentes :

>>> "Alice" not in t >>> not ("Alice" in t)

⚙ 05° Créer un programme qui stocke le tableau eleves, stocke le nombre d'élèves dans une variable nb et stocke dans mystere le nom de l'élève d'indice 75 et dans mystere2 le nom de l'élève du 75e élève.

eleves = ["Lisa", "Scott", "Matthias", "Antoine", "Ethan", "Lucas", "Manon", "Alexandre", "Alexandre", "Kenzo", "Thomas", "Lilou", "Aurélien", "Charles", "Manon", "Francia", "Imrane", "Sarah", "Yassin", "Sofian", "Noé", "Lenny", "Matt", "Ryiad", "Yanis", "Jason", "Damien", "Antonin", "Samy", "Laurine", "Rayan", "Eliot", "Victor", "Theo", "Julien", "Benjamin", "Flavian", "Nathan", "Nassim", "Evan", "Hugo", "Quentin", "Gwennaël", "Sullyvan", "Mathias", "Yanis", "Mathis", "Simon", "Mathis", "Matthew", "Brandon", "Axelle", "Mathieu", "Stéphane", "Hadrien", "Thomas", "Anton", "Thomas", "Djason", "Lohan", "Kylian", "Corentin", "Julien", "Léa", "Laura", "Anthony", "Audrey", "Léo", "Reda", "Ayoub", "Quentin", "Maïssa", "Tanguy", "Giovanni", "Mélia", "Gwenaël", "Ismaël", "Thomas", "Victor", "Andrew", "Théo", "Florian", "Louis", "Djebrine", "Angele", "Loann", "Medhi", "Jordy", "Pierre", "Kylian"]

...CORRECTION...

1 2 3 4 5
eleves = ["Lisa", "Scott", "Matthias", "Antoine", "Ethan", "Lucas", "Manon", "Alexandre", "Alexandre", "Kenzo", "Thomas", "Lilou", "Aurélien", "Charles", "Manon", "Francia", "Imrane", "Sarah", "Yassin", "Sofian", "Noé", "Lenny", "Matt", "Ryiad", "Yanis", "Jason", "Damien", "Antonin", "Samy", "Laurine", "Rayan", "Eliot", "Victor", "Theo", "Julien", "Benjamin", "Flavian", "Nathan", "Nassim", "Evan", "Hugo", "Quentin", "Gwennaël", "Sullyvan", "Mathias", "Yanis", "Mathis", "Simon", "Mathis", "Matthew", "Brandon", "Axelle", "Mathieu", "Stéphane", "Hadrien", "Thomas", "Anton", "Thomas", "Djason", "Lohan", "Kylian", "Corentin", "Julien", "Léa", "Laura", "Anthony", "Audrey", "Léo", "Reda", "Ayoub", "Quentin", "Maïssa", "Tanguy", "Giovanni", "Mélia", "Gwenaël", "Ismaël", "Thomas", "Victor", "Andrew", "Théo", "Florian", "Louis", "Djebrine", "Angele", "Loann", "Medhi", "Jordy", "Pierre", "Kylian"] nb = len(eleves) mystere = eleves[75] mystere2 = eleves[74]

✌ 06° Créer une variable cours_lundi référençant un tableau de strings de 11 cases :

  • Indice 0 : le nom de la journée : "lundi".
  • Indice 1 : le nom du cours que vous avez de 8h à 9h
  • Indice 2 : le nom du cours que vous avez de 9h à 10h
  • Indice 3 : le nom du cours que vous avez de 10h à 11h
  • Indice 4 : le nom du cours que vous avez de 11h à 12h
  • Indice 5 : le nom du cours que vous avez de 12h à 13h
  • Indice 6 : le nom du cours que vous avez de 13h à 14h
  • Indice 7 : le nom du cours que vous avez de 14h à 15h
  • Indice 8 : le nom du cours que vous avez de 15h à 16h
  • Indice 9 : le nom du cours que vous avez de 16h à 17h
  • Indice 10 : le nom du cours que vous avez de 17h à 18h

Si vous n'avez pas cours sur le créneau, on insère un string "-" puisqu'on veut que ce soit un tableau de strings.

Exemple de début de déclaration si le lundi vous n'avez rien de 8h à 9h puis NSI de 9h à 10h.

>>> cours_lundi = ['lundi', "-", "NSI", ...

Deuxième question : une fois la variable en mémoire, que faut-il taper dans la console pour avoir le cours de 14h à 15h à partir de votre variable cours ?

⚙ 07° Compléter la fonction afficher_les_cours() pour qu'elle parvienne à afficher correctement les cours de la journée transmise. Le paramètre journee est bien entendu un tableau similaire à celui de la question précédente.

...AIDE...

Si on analyse le programme fourni, on voit :

  • Une déclaration de fonction afficher_les_cours() en ligne 1. On voit que lors de l'appel à cette fonction, il faudra lui envoyer quelque chose qu'elle placera dans une variable nommée journee.
  • Un appel à afficher_les_cours() en ligne 7. Cette ligne n'est là que pour vous proposez un exemple : vous pouvez modifier l'appel et lui demander de travailler sur autre chose.

Vous devez donc travailler en considérant que vous ne savez pas ce que contient exactement journee mais qu'il s'agit bien d'un tableau contenant les informations sur le jour de la semaine puis les cours sur les différents créneaux.

1 2 3 4 5 6 7
def afficher_les_cours(journee): for ... print(...) cours_mardi = ["mardi", "Math", "Math", "NSI", "NSI", "-", "Français", "Anglais", "-", "-", "-", "-"] afficher_les_cours(cours_mardi)

...CORRECTION...

1 2 3 4 5 6 7
def afficher_les_cours(journee): for i in range(len(journee)): print(journee[i]) cours_mardi = ["mardi", "Math", "Math", "NSI", "NSI", "-", "Français", "Anglais", "-", "-", "-", "-"] afficher_les_cours(cours_mardi)

⚙ ✌ 08° Compléter et commenter la fonction nb_heures() pour qu'elle parvienne à renvoyer le nombre d'heures de cours durant la journée transmise. Donc tout sauf les "-". Le paramètre journee est bien entendu un tableau similaire à celui de la question précédente. Avant de répondre, pensez bien à gérer le fait que la première case contient en réalité le nom de la journée et qu'il ne faut donc pas la compter.

...AIDE...

Si on analyse le programme fourni, on voit :

  • Une déclaration de fonction nb_heures() en ligne 1. On voit que lors de l'appel à cette fonction, il faudra lui envoyer quelque chose qu'elle placera dans une variable nommée journee.
  • Un appel à nb_heures() en ligne 10. Cette ligne n'est là que pour vous proposez un exemple : vous pouvez modifier l'appel et lui demander de travailler sur autre chose.

Vous devez donc travailler en considérant que vous ne savez pas ce que contient exactement journee mais qu'il s'agit bien d'un tableau contenant les informations sur le jour de la semaine puis les cours sur les différents créneaux.

1 2 3 4 5 6 7 8 9 10
def nb_heures(journee): compteur = 0 for ...: if ... != ...: compteur = compteur + ... return ... - ... cours_mardi = ["mardi", "Math", "Math", "NSI", "NSI", "-", "Français", "Anglais", "-", "-", "-", "-"] reponse = nb_heures(cours_mardi)

Après exécution du programme, la variable reponse devrait donc ici contenir 6.

...CORRECTION...

1 2 3 4 5 6 7 8 9 10
def nb_heures(journee): compteur = 0 for i in range(len(journee)): # Pour chaque indice i du tableau journee if journee[i]!= '-': # Si le contenu de la case i n'est pas un créneau vide compteur = compteur + 1 # On incrémente le compteur return compteur - 1 # On enlève 1 car la première case du jour active un "créneau" cours_mardi = ["mardi", "Math", "Math", "NSI", "NSI", "-", "Français", "Anglais", "-", "-", "-", "-"] reponse = nb_heures(cours_mardi)

4 - n-uplet

La différence majeure entre un tableau et un n-uplet vient du fait qu'on peut placer des éléments de type différent dans chacune des cases.

Imaginons qu'on désire stocker des informations sur un individu :

1 2 3 4
nom = "In Borderland" prenom = "Alice" age = 18 speNSI = True

On voit bien qu'on veut stocker 2 strings, un entier et un booléen. Dans un tableau statique, ce n'est pas possible.

4.1 n-UPLET : définition

Généralités

Un n-uplet est un conteneur formant une collection ordonnée d'éléments pouvant avoir un type différent les uns des autres.

Les cases sont identifiées par un numéro nommé indice (index en anglais).

Voici deux exemples de n-uplets :

Un 2-uplet dont les indices sont 0-1 

Indice 0 1
Elément 'DS' 18

Un 4-uplet dont les indices sont 0-1-2-3 :

Indice 0 1 2 3
Elément "In Bordeland" "Alice" 18 True
Noms usuels de quelques n-uplets particuliers :
  • 1-uplet : singleton
  • 2-uplet : couple
  • 3-uplet : triplet
  • 4-uplet : quadruplet

Le mot français uplet se traduit par tuple en anglais.

flowchart LR V([Variable]) --> M([conteneur-tuple]) M -- indice 0 --> A([InBorderLand]) M -- indice 1 --> B([Alice]) M -- indice 2 --> C([18]) M -- indice 3 --> D([True])

Notez bien que la première case est la case d'indice 0, pas celle d'indice 1. Si un tableau possède 20 cases, les indices disponibles vont de 0 à 19.

4.2 n-UPLET : déclaration avec Python

Type tuple

Les tuples sont implémentés en Python sous forme d'une structure de données dont le type se nomme tuple.

Déclaration (avec des parenthèses)

On peut enregistrer une séquence de données dans un tuple en utilisant la syntaxe suivante :

  • une parenthèse ( en ouverture,
  • une parenthèse ) en fermeture et
  • des virgules pour séparer les valeurs.

Exemple avec un élève : nom, prénom, age, NSI ou pas :

>>> eleve = ("In Bordeland", "Alice", 18, True) >>> eleve ('In Bordeland', 'Alice', 18, True) >>> type(eleve) <class 'tuple'>
Déclaration d'un grand tuple

On peut déclarer un tuple sur plusieurs lignes et tapant sur ENTREE après chaque virgule. Exemple :

1 2 3 4 5
eleve = ("In Borderland", "Alice", 18, True )

Cela prend plus de lignes mais on comprend un peu mieux ce qu'on place où.

Déclaration d'un tuple vide

Deux solutions

>>> tup = () >>> tup () >>> tup = tuple() >>> tup () >>> bool(tup) # tup est ici un contenu "vide" False
Cas particulier du singleton

Pour déclarer un tuple de 1 élément, il faut nécessairement placer une virgule, sinon l'interpréteur Python prendra vos parenthèses comme de simples parenthèses.

Correct pour du tuple :

>>> tp1 = (10,) >>> tp1 (10,) >>> type(tp1) <class 'tuple'>

Incorrect pour du tuple :

>>> tp2 = (10) >>> tp2 10 >>> type(tp2) <class 'int'>
4.3 n-UPLET : opérateurs Python

CONCATÉNATION avec +

tuple + tuple -> tuple

>>> (10, 20) + (5, 30) (10, 20, 5, 30)

Concaténation (tuple) : coût LINÉAIRE par rapport au nombre n d'éléments.


RÉPÉTITION avec *

tuple * int -> tuple

int * tuple -> tuple

>>> (10,) * 3 (10, 10, 10) >>> 3 * (10, 12) (10, 12, 10, 12, 10, 12)

Répétition (tuple) : coût LINÉAIRE par rapport au nombre n d'éléments.

Erreur sémantique courante

Nous avions vu l'erreur sémantique suivante :

>>> 5,2 + 1,2 (5, 3, 2)

Pour la comprendre, il faut se rendre compte qu'on demande à Python d'interpréter un tuple !

Voici ce que comprend l'intepréteur Python :

>>> (5,2 + 1,2) (5, 3, 2)

On lui demande donc d'évalue un triplet contenant 5 sur l'indice 0, 2 + 1 sur l'indice 1 et 2 sur l'indice 2.

Moralité : explicite c'est mieux qu'implice.

4.4 n-UPLET : accéder à une case avec [i]

Accès (avec les crochets)

On peut accéder à l'élément stocké dans une case dont on connait l'indice en tapant simplement le nom de la variable-tuple suivie de crochets et du numéro d'indice.

Attention, on place des crochets pour accéder, les parenthèses c'est pour la déclaration.

Indice 0 1 2 3 >>> eleve = ("In Bordeland", "Alice", 18, True) >>> eleve[0] 'In Bordeland' >>> eleve[1] 'Alice' >>> eleve[2] 18 >>> eleve[3] True >>> eleve[4] IndexError: tuple index out of range

Accès en lecture (tuple) : coût CONSTANT par rapport au nombre n d'éléments.

Trois choses à distinguer
  • Le conteneur tup (le n-uplet)
  • Les indices i
  • Les contenus tup[i]
4.5 n-UPLET : déterminer sa longueur

La longueur d'un tuple correspond au nombre de "cases-éléments" du tuple.

On utilise la fonction native len().

Indice 0 1 2 3 >>> eleve = ("In Bordeland", "Alice", 18, True) >>> len(eleve) 4

4 éléments, on sait alors qu'on peut demander des indices allant de 0 à 3.

Longueur (tuple) : coût CONSTANT par rapport au nombre n d'éléments car cette longueur est mémorisée en réalité.

4.6 n-UPLET : immuable en Python (pas de modification)

En Python, les tuples sont immuables (ou non mutables en anglais) : on ne peut pas modifier le contenu d'une case après la création du n-uplet.

Imaginons qu'on veuille mettre les informations sur Alice à jour le jour de ses 19 ans :

Indice 0 1 2 3 >>> eleve = ("In Bordeland", "Alice", 18, True) >>> eleve[2] = 19 TypeError: 'tuple' object does not support item assignment
4.7 n-UPLET : parcours par indices

On utilise une boucle for i in range(len(tup)).

Ainsi avec ("In Borderland", "Alice", 18, True ), on a 4 éléments d'indices 0 à 3.

1 2 3 4
eleve = ("In Borderland", "Alice", 18, True) for i in range(len(eleve)): # Pour chaque indice possible dans eleve print(eleve[i]) # Affiche le contenu de la case i

Ce programme est équivalent à ceci :

1 2 3 4 5 6
eleve = ("In Borderland", "Alice", 18, True) print(eleve[0]) print(eleve[1]) print(eleve[2]) print(eleve[3])

Ils affichent l'un et l'autre ceci dans la console :

'In Borderland' 'Alice' 18 True

Accès à toutes les cases (tuple) : coût LINÉAIRE par rapport au nombre n d'éléments.

4.8 n-UPLET : mot-clés in et not in

Fonctionne exactement comme avec les tableaux, si ce n'est que ce sont des tuples.

Test d'appartenance ou de présence

On utilise l'opérateur binaire in qui renvoie un booléen.

Pour savoir si le contenu est présent dans le tuple tup, on tape contenu in tup.

>>> "Alice" in ("Alice", "Bob", "Charlie") True >>> "Dana" in ("Alice", "Bob", "Charlie") False

Traduction : "Alice" est-elle présente dans la liste des élèves ? "Dana" est-elle présente dans la liste ?

Appartenance : coût LINÉAIRE par rapport au nombre n d'éléments.

Test de non-appartenance ou d'absence

On utilise l'opérateur binaire not in qui renvoie un booléen.

Pour savoir si le contenu n'est pas présent dans le tuple tup, on tape contenu not in t.

>>> "Alice" not in ("Alice", "Bob", "Charlie") False >>> "Dana" not in ("Alice", "Bob", "Charlie") True

Traduction : "Alice" est-elle absente de la liste des élèves ? "Dana" est-elle absente de la liste ?

⚙ 09° L'encodage ASCII des caractères fait correspondre un nombre compris entre 0 et 127 à quelques caractères. Dans la mesure où la correspondance est figée, nous allons la stocker dans un tuple immuable plutôt que dans un tableau muable.

ascii = ('\x00', '\x01', '\x02', '\x03', '\x04', '\x05', '\x06', '\x07', '\x08', '\t', '\n', '\x0b', '\x0c', '\r', '\x0e', '\x0f', '\x10', '\x11', '\x12', '\x13', '\x14', '\x15', '\x16', '\x17', '\x18', '\x19', '\x1a', '\x1b', '\x1c', '\x1d', '\x1e', '\x1f', ' ', '!', '"', '#', '$', '%', '&', "'", '(', ')', '*', '+', ',', '-', '.', '/', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?', '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '[', '\\', ']', '^', '_', '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '{', '|', '}', '~', '\x7f')

Deux questions

  1. Afficher le caractère ayant l'indice 65 en utilisant le tuple ascii ci-dessous.
  2. Trouver le message qui se cache derrière la suite d'indices 67-111-117-99-111-117.

...CORRECTION...

On place ceci dans un programme et on lance pour le mettre en mémoire.

1
ascii = ('\x00', '\x01', '\x02', '\x03', '\x04', '\x05', '\x06', '\x07', '\x08', '\t', '\n', '\x0b', '\x0c', '\r', '\x0e', '\x0f', '\x10', '\x11', '\x12', '\x13', '\x14', '\x15', '\x16', '\x17', '\x18', '\x19', '\x1a', '\x1b', '\x1c', '\x1d', '\x1e', '\x1f', ' ', '!', '"', '#', '$', '%', '&', "'", '(', ')', '*', '+', ',', '-', '.', '/', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?', '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '[', '\\', ']', '^', '_', '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '{', '|', '}', '~', '\x7f')

Il suffit alors d'interroger l'interpréteur :

>>> ascii[65] 'A' >>> ascii[67] 'C' >>> ascii[111] 'o' >>> ascii[117] 'u' >>> ascii[99] 'c' >>> ascii[111] 'o' >>> ascii[117] 'u'

⚙ 10° Compléter le programme pour parvenir à afficher le message : les cases contiennent les codes ASCII des caractères du message. Rajouter des commentaires de façon à rendre ce programme compréhensible.

Vous remarquerez que le print() possède un paramètre supplémentaire nommé end configuré pour remplacer le passage à la ligne (qui est la solution par défaut) par ... rien ("") ici à la fin de chaque print. De cette façon, les caractères s'afficheront les uns derrières les autres sur la même ligne.

1 2 3 4 5 6 7 8 9 10
ascii = ('\x00', '\x01', '\x02', '\x03', '\x04', '\x05', '\x06', '\x07', '\x08', '\t', '\n', '\x0b', '\x0c', '\r', '\x0e', '\x0f', '\x10', '\x11', '\x12', '\x13', '\x14', '\x15', '\x16', '\x17', '\x18', '\x19', '\x1a', '\x1b', '\x1c', '\x1d', '\x1e', '\x1f', ' ', '!', '"', '#', '$', '%', '&', "'", '(', ')', '*', '+', ',', '-', '.', '/', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?', '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '[', '\\', ']', '^', '_', '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '{', '|', '}', '~', '\x7f') message = [67, 111, 117, 99, 111, 117] for i in ... valeur = ...[...] caractere = ...[...] print(..., end="") print("")

Une fois votre programme fonctionnel, vous devriez voir Coucou s'afficher dans la console.

...CORRECTION...

1 2 3 4 5 6 7 8 9 10
ascii = ('\x00', '\x01', '\x02', '\x03', '\x04', '\x05', '\x06', '\x07', '\x08', '\t', '\n', '\x0b', '\x0c', '\r', '\x0e', '\x0f', '\x10', '\x11', '\x12', '\x13', '\x14', '\x15', '\x16', '\x17', '\x18', '\x19', '\x1a', '\x1b', '\x1c', '\x1d', '\x1e', '\x1f', ' ', '!', '"', '#', '$', '%', '&', "'", '(', ')', '*', '+', ',', '-', '.', '/', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?', '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '[', '\\', ']', '^', '_', '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '{', '|', '}', '~', '\x7f') message = [67, 111, 117, 99, 111, 117] for i in range(len(message)): # pour chaque indice possible de message valeur = message[i] # on récupère la valeur contenu dans la case n°i caractere = ascii[valeur] # on cherche le caractère qui correspond à la case n°valeur dans ascii print(caractere, end="") # on affiche le caractère sans passer à la ligne print("") # passage à la ligne final

5 - Dictionnaire

Parfois, on ne connaît pas nécessairement les informations qu'on va vouloir stocker.

Imaginons qu'on veuille compter le nombre de fois où chaque mot est présent dans une phrase. Deux raisons de ne pas utiliser de tableau ou de n-uplet :

  1. Au vu du nombre de mots possibles, pas moyen de créer un tableau statique ou un n-uplet, il y aurait beaucoup trop de cases (et la majorité des cases seraient vides).
  2. Comment connaître l'indice d'un mot qu'on cherche ? Ca peut vite être long s'il faut lire les cases une par une depuis le début à chaque fois...

Dans ce cas, la meilleure solution est le dictionnaire.

(Rappel) 5.1 DICTIONNAIRE : définition

Définitions

Un dictionnaire est un tableau associatif. Un dictionnaire est une collection non ordonnée d'éléments (contrairement aux tableaux et n-uplets où les éléments sont ordonnés via leurs indices).

Il comporte donc des cases qui portent un nom et possèdent un contenu.

Clé "Alice" "Bob" "Charlie"
Valeur 13 8 12

On nomme :

  • clé (key en anglais) le nom de la case.
  • valeur (value en anglais) le contenu de la case.
Différencier le conteneur et le contenu

Le nom du dictionnaire permet de localiser le conteneur, connaître la clé permet de savoir à quelle case du conteneur accéder.

flowchart LR D([Variable notes]) --> M([conteneur-dictionnaire]) M -- Clé Alice --> A([13]) M -- Clé Bob --> B([8]) M -- Clé Charlie --> C([12])
(Rappel) 5.2 DICTIONNAIRE : déclaration

Le type de l'objet dictionnaire (dictionary en anglais) dans Python se nomme dict.

Déclaration (avec les accolades)
  • Les éléments délimiteurs sont les accolades {}.
  • On fournit un couple (cle, valeur) en utilisant la syntaxe Python suivante : clevaleur.
  • Chaque couple est séparé des autres par une virgule.

Exemple avec le dictionnaire décrivant un devoir surveillé :

1
ds = {"Alice": 13, "Bob": 8, "Charlie": 12}
Déclaration d'un grand dictionnaire

Sachez qu'on peut déclarer un dictionnaire sur plusieurs lignes en tapant sur ENTREE après chaque virgule. Exemple :

1 2 3 4 5
ds = { "Alice": 13, "Bob": 8, "Charlie": 12 }
Les dictionnaires : type dict en Python
>>> ds = {"Alice": 13, "Bob": 8, "Charlie": 12} >>> type(ds) <class 'dict'>
Déclaration d'un dictionnaire vide

Deux solutions

>>> d = {} >>> d {} >>> d = dict() >>> d {} >>> bool(d) # d est vide ici False
5.3 DICTIONNAIRE : opérateurs Python

Ni concaténation, ni répétition.

C'est fini.

(Rappel) 5.4 DICTIONNAIRE : accés à une valeur avec [cle]

Accès (avec des crochets)

Pour accéder à la valeur d'une case, il faut connaître sa clé. On accède à une valeur en tapant le nom du dictionnaire suivi de la clé entre crochets.

Attention, on place des crochets pour accéder, les accolades c'est pour la déclaration.

>>> ds = {"Alice": 13, "Bob": 8, "Charlie": 12} >>> ds["Alice"] 13 >>> ds["Charlie"] 12 >>> ds["Bob"] 8 >>> ds["Bob l'éponge"] KeyError: "Bob l'éponge"

Comme vous le voyez, demander un accès avec une clé inconnue provoque une erreur.

Accès (dict) : coût CONSTANT par rapport au nombre n d'éléments.

Résumé
  • Si d est un dictionnaire,
  • Si c est une clé valide dans le dictionnaire,
  • Alors d[c] est le contenu associé à la clé c du dictionnaire d,
5.5 DICTIONNAIRE : déterminer sa longueur

On peut utiliser la fonction native len() pour obtenir le nombre de couples (clé, valeur) enregistrés dans un dictionnaire.

Exemple

>>> ds = {"Alice": 13, "Bob": 8, "Charlie": 12} >>> nbr = len(ds) >>> nbr 3

Longueur (dict) : coût CONSTANT par rapport au nombre n d'éléments.

5.6 DICTIONNAIRE : muable en Python (modification possible)

En Python, les dictionnaires sont muables (ou mutables en anglais) : on peut modifier le contenu d'une case après la création du dictionnaire.

Modification d'un couple existant

Imaginons qu'on ai oublié des points à Bob : il n'a pas 8 mais 11 finalement. Voici comment nous pourrions modifier le tableau APRES création

>>> {"Alice": 13, "Bob": 8, "Charlie": 12} >>> notes["Bob"] 8 >>> notes["Bob"] = 11 >>> notes["Bob"] 11 >>> notes {'Alice': 13, 'Bob': 11, 'Charlie': 12}

Notez bien que ce n'est pas une affectation sur le dictionnaire : l'affectation est faite sur l'un des contenus des associations clé-valeur du dictionnaire, pas sur le dictionnaire lui-même.

Accès en modification (dict) : coût CONSTANT par rapport au nombre n d'éléments.

Rajout d'un nouveau couple

On peut rajouter de la même façon un couple qui n'existe pas encore.

Imaginons un nouvel élève nommé David qui a eu 15.

>>> {"Alice": 13, "Bob": 11, "Charlie": 12} >>> notes["David"] = 15 >>> notes {'Alice': 13, 'Bob': 11, 'Charlie': 12, 'David': 15}
5.7 DICTIONNAIRE : parcours par clés

On utilise une boucle for .. in mais on ne peut pas la coupler à la fonction len puisqu'un dictionnaire possède des clés, pas des indices.

Voici la manière usuelle d'obtenir les clés une par une.

1 2 3 4
ds = {"Alice": 13, "Bob": 8, "Charlie": 12} for cle in ds.keys(): # Pour chaque cle possible dans ds print(ds[cle]) # Affiche la valeur associée à cette clé

Ce programme est équivalent à ceci :

1 2 3 4 5
ds = {"Alice": 13, "Bob": 8, "Charlie": 12} print(ds["Alice"]) print(ds["Bob"]) print(ds["Charlie"])

Ils affichent l'un et l'autre ceci dans la console :

13 8 12

Accès à toutes les cases (dict) : coût LINÉAIRE par rapport au nombre n d'éléments.

5.8 DICTIONNAIRE : mot-clés in et not in

Test d'existence d'une clé

On utilise l'opérateur binaire in qui renvoie un booléen.

Pour savoir si la cle est une clé dans le dictionnaire d, on tape cle in d.

Version explicite :

>>> d = {"Alice": 12, "Bob": 8} >>> "Alice" in d.keys() True >>> "Dana" in d.keys() False

Version implicite :

>>> d = {"Alice": 12, "Bob": 8} >>> "Alice" in d True >>> "Dana" in d False

Traduction : "Alice" est-elle une clé présente dans le dictionnaire d ? "Dana" est-elle une clé présente dans le dictionnaire d ?

Existence d'une clé (dict) : coût CONSTANT par rapport au nombre n d'éléments.

L'explication viendra en Terminale.

Test d'absence d'une clé

On utilise l'opérateur binaire not in qui renvoie un booléen.

Pour savoir si la cle n'est pas une clé dans le dictionnaire d, on tape cle not in d.

Voici la version explicite :

>>> d = {"Alice": 12, "Bob": 8} >>> "Alice" not in d.keys() False >>> "Dana" not in d.keys() True

Voici la version implicite :

>>> d = {"Alice": 12, "Bob": 8} >>> "Alice" not in d False >>> "Dana" not in d True

Traduction : "Alice" est-elle absente en tant que clé dans le dictionnaire ? "Dana" est-elle absente en tant que clé dans le dictionnaire ?

⚙ 11° Nous allons créer un dictionnaire qui contient l'emploi du temps sur la journée du lundi.

  • Les clés seront des strings du type "10-11" correspondant aux horaires de vos cours du lundi
  • Les valeurs associées devront être les intitulés des cours ("NSI", "Math", "LLCER"...)

Si vous n'avez pas cours sur le créneau, pas la peine de créer de clés pour ce créneau. On verra qu'il n'y a pas cours car la clé n'existe pas.

  1. Créer une variable cours_du_lundi référençant un dictionnaire.

    Pensez à utiliser une déclaration sur plusieurs lignes, avec un seul couple clé: valeur par ligne, si vous voulez que cela soit facilement compréhensible.

  2. Comment accèder au cours de 14h à 15h à partir de votre variable cours_du_lundi ?
  3. Peut-on le faire sans danger ou faut-il vérifier quelque chose avant ?

...CORRECTION...

1 2 3 4 5 6 7 8
cours_lundi = { "8-9": "Math", "9-10": "Math", "10-11": "NSI", "11-12": "NSI", "14-15": "Anglais", "15-16": "Français" }

On doit taper cours_lundi["14-15"].

Attention : on ne peut pas le faire sans risque car si la clé n'existe pas, cela provoque une exception. Avant de lancer l'accès, il faut tester la clé avec l'opérateur in.

⚙ 12° Compléter la fonction afficher_les_cours() pour qu'elle parvienne à afficher correctement les cours de la journée transmise. Le paramètre journee est bien entendu un dictionnaire similaire à celui de la question précédente.

...AIDE...

Si on analyse le programme fourni, on voit :

  • Une déclaration de fonction afficher_les_cours() en ligne 1. On voit que lors de l'appel à cette fonction, il faudra lui envoyer quelque chose qu'elle placera dans une variable nommée journee.
  • Un appel à afficher_les_cours() en ligne 14. Cette ligne n'est là que pour vous proposez un exemple : vous pouvez modifier l'appel et lui demander de travailler sur autre chose.

Vous devez donc travailler en considérant que vous ne savez pas ce que contient exactement journee mais qu'il s'agit bien d'un dictionnaire dont les clés sont les horaires et les valeurs associées le cours sur ce créneau.

1 2 3 4 5 6 7 8 9 10 11 12 13 14
def afficher_les_cours(journee): for ... print(...) cours_lundi = { "8-9": "Math", "9-10": "Math", "10-11": "NSI", "11-12": "NSI", "14-15": "Anglais", "15-16": "Français" } afficher_les_cours(cours_lundi)

...CORRECTION...

1 2 3 4 5 6 7 8 9 10 11 12 13 14
def afficher_les_cours(journee): for cle in journee.keys(): # Pour chaque cle possible dans journee print(journee[cle]) # Affiche la valeur associée à cette clé cours_lundi = { "8-9": "Math", "9-10": "Math", "10-11": "NSI", "11-12": "NSI", "14-15": "Anglais", "15-16": "Français" } afficher_les_cours(cours_lundi)

⚙ ✌ 13° Expliquer à quoi sert ce programme en commentant chaque ligne en lui donnant du sens :

Remarque : la ligne 11 ne sert qu'à faire une pause le temps que l'utilisateur appuie sur ENTREE. De cette façon, la boucle se fait au rythme que vous voulez.

Une fois que vous avez compris le principe, vous pouvez placer un # au début de la ligne 11 (pour n'en faire qu'un commentaire) ou la supprimer totoalement.

1 2 3 4 5 6 7 8 9 10 11
txt = "Linux ou GNU/Linux est une famille de systèmes d'exploitation open source de type Unix fondés sur le noyau Linux créé en 1991 par Linus Torvalds. De nombreuses distributions Linux ont depuis vu le jour et constituent un important vecteur de popularisation du mouvement du logiciel libre." compteur = {} for i in range(len(txt)): caractere = txt[i] if caractere in compteur.keys(): compteur[caractere] = compteur[caractere] + 1 else: compteur[caractere] = 1 print(compteur) input()

🏠 TRAVAIL PERSONNEL° Réaliser les exercices supplémentaires Maison (voir le lien) en rédigeant correctement vos réponses.

Exercices

BILAN EN CLASSE° Répondre aux questions proposées puis fournir le déroulé des lignes suivies par l'interpréteur lancé sur le programme ci-dessous.

    Si t fait référence à un tableau :

  1. Que veut dire à priori i ?
  2. Que veut dire à priori t[i] ?
  3. Que veut dire à priori t ?
  4. Que veut dire à priori len(t) ?
  5. Que veut dire à priori for i in range(len(t)): ?
  6. Si t = [10, 20, 12] :

  7. Quelle est l'évaluation de t[0] ?
  8. Quelle est l'évaluation de t[1] ?
  9. Quelle est l'évaluation de t[2] ?
  10. Quelle est l'évaluation de len(t) ?
  11. Quelles sont les valeurs prises successivement par i avec for i in range(len(t)): ?
  12. Fournir les lignes que va exécuter l'interpréteur Python au fur et à mesure de l'éxécution du programme.
  13. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
    def somme(t): s = 0 for i in range(len(t)): s = s + t[i] return s def moyenne(t): total = somme(t) nbr = len(t) return total / nbr moy = {} notes_alice = [10, 15, 20] notes_bob = [10, 14] moy["alice"] = moyenne(notes_alice) moy["bob"] = moyenne(notes_bob)

6 - Convertir en tableau

Les 4 dernières parties ne contiennent pas de choses à connaître par coeur pour le moment. Mais la plupart des transformations vues ici vont nous permettre de gérer correctement les données dans la plupart des TP.

Votre objectif ici est donc de comprendre comment cela fonctionne et de savoir où retrouver l'information.

6.1 - listlist avec list()

list vers list : faire une copie rapide

Utiliser list() sur un autre tableau permet d'en faire une copie peu profonde.

>>> t = [1, 2, 4] # création d'un tableau >>> t2 = t # t2 n'est qu'un alias, un autre nom pour le même tableau ! >>> t3 = list(t) # t3 est une copie indépendante1 >>> t[0] = 100 # on modifie le contenu de la case 0 par 100 >>> t [100, 2, 4] # Modifié : normal >>> t2 [100, 2, 4] # Modifié : normal, c'est un alias de t ! >>> t3 [1, 2, 4] # Non modifié : normal, c'est une copie.

Remarque 1 : la notion de copie indépendante n'est valable que si les éléments contenus sont des types simples.

6.2 - tuplelist avec list()

tuple vers list

Utiliser list() sur un tuple permet de faire une copie muable des données du tuple immuable.

>>> tup = (1, 2, 4) # création d'un 3-uplet >>> t = list(tup) # t est une copie muable de tup >>> t[0] = 100 # on modifie le contenu de la case 0 par 100 >>> t [100, 2, 4] # Modifié : normal >>> tup (1, 2, 4) # tup immuable de toutes manières !
Attention aux types

Cette conversion ne posera jamais de problèmes en Python mais souvenez vous que dans certains langages un tableau ne peut contenir qu'un unique type de données.

Ainsi, l'exemple suivant ne fonctionnera pas dans tous les langages :

>>> tup = ("Alice", 2) # création d'un couple >>> t = list(tup) # t est une copie muable de tup >>> t ['Alice', 2]
6.3 - dictlist avec list()

dict vers list

Utiliser list() sur un dictionnaire d permet de récupérer :

  • Uniquement les clés en fournissant d ou d.keys() explicitement;
  • Uniquement les valeurs en fournissant d.values() explicitement;
  • Les couples (clé, valeur)en fournissant d.items() explicitement.
>>> d = {'Alice':14, 'Bob':12} # création d'un dictionnaire >>> t1 = list(d) # IMPLICITE : t contient les clés de d >>> t1 ['Alice', 'Bob'] >>> t2 = list(d.keys()) # EXPLICITE : t contient les clés de d >>> t2 ['Alice', 'Bob'] >>> t3 = list(d.values()) # EXPLICITE : t contient les valeurs de d >>> t3 [14, 12] >>> t4 = list(d.items()) # EXPLICITE : t contient les couples de d >>> t3 [('Alice', 14), ('Bob', 12)]
6.4 strlist avec list() : récupérer les caractères

Un string est un conteneur de caractères.

On peut donc les placer dans un autre conteneur, par exemple un tableau.

Pour cela, le plus simple est d'utiliser la fonction native list() qui tente de créer un tableau à partir des données fournies en entrée.

Récupérer les caractères dans un tableau

Il suffit d'utiliser la fonction native list().

>>> nom = "Merlin ou Toto l'asticot" >>> t = list(nom) >>> t ['M', 'e', 'r', 'l', 'i', 'n', ' ', 'o', 'u', ' ', 'T', 'o', 't', 'o', ' ', 'l', "'", 'a', 's', 't', 'i', 'c', 'o', 't']
6.5 strlist avec split() récupérer les éléments structurants d'un string

Une phrase est un ensemble de mots séparés par des espaces notamment.

La méthode split() veut dire séparer et permet justement de "séparer" un string en différentes parties et placer ces parties dans un tableau.

Récupérer les mots d'une phrase

On utilise la méthode split() en précisant que le caractère de séparation est l'espace.

>>> nom = "Merlin ou Toto l'asticot" >>> t = nom.split(' ') >>> t ['Merlin', 'ou', 'Toto', "l'asticot"]
Spliter sans rien fournir

Par défaut, il est possible de ne pas préciser le caractère qui servira à scinder le string en plusieurs parties : la méthode est configurée pour considérer qu'il s'agit de l'espace.

>>> nom = "Merlin ou Toto l'asticot" >>> t = nom.split() >>> t ['Merlin', 'ou', 'Toto', "l'asticot"]
Récupérer les phrases ?

Pour récupérer les phrases, on peut considérer qu'il suffit d'utiliser la méthode en considérant que le caractère séparateur est le point.

⚙ 14° Vous allez voir cette année qu'un moyen d'identifier les ordinateurs est d'utiliser une adresse IPv4 caractérisée par 4 nombres séparés par des points :

Exemples :
80.100.15.3
80.120.30.250

Questions

  1. Si on utilise un string pour caractériser cette adresse (exemple "80.100.15.3"), quel est le caractère qui sépare les différents éléments de cette adresse ?
  2. Que faut-il taper pour récupérer dans un tableau les 4 valeurs d'une adresse reçue sous forme d'un string ?
  3. >>> ip = "80.100.15.3" >>> t = ???
  4. Que faut-il taper pour récupérer uniquement la première valeur et la convertir en entier ?
  5. >>> ...( t[...])

...CORRECTION...

>>> ip = "80.100.15.3" >>> t = ip.split(".") >>> t ['80', '100', '15', '3'] >>> int( t[0] ) 80

⚙ 15° Vous allez voir cette année qu'une adresse de site se décompose en plusieurs noms séparés par des points :

Exemples :
www.infoforall.fr
www.nuitducode.net

Questions

  1. Si on utilise un string pour caractériser cette adresse (exemple "www.infoforall.fr"), quel est le caractère qui sépare les différents éléments de cette adresse ?
  2. Que faut-il taper pour récupérer dans un tableau les différents parties de cette adresse reçue sous forme d'un string ?
  3. >>> adr = "www.infoforall.fr" >>> t = ???
  4. Que faut-il taper pour récupérer l'extension (le .fr) sur l'exemple ?
  5. >>> t[???]

...CORRECTION...

>>> adr = "www.infoforall.fr" >>> t = adr.split(".") >>> t ['www', 'infoforall', 'fr'] >>> t[2] 'fr'

⚙ 16° Vous allez revoir cette année le principe du stockage d'informations dans un fichier CSV : Comma Separeded Value. Chaque enregistrement est juste une ligne sur laquelle les informations sont séparérs par une "virgule". :

Exemples :
"Alice;16 ans;Math;NSI;PC"
"Bob;15 ans;Math;NSI;SES"

Questions

  1. Quel est le caractère qui sépare les différents éléments de cet enregistrement ?
  2. Que faut-il taper pour récupérer dans un tableau les différentes informations ?
  3. >>> e = "Alice;16 ans;Math;NSI;PC" >>> t = ???
  4. Comment récupérer uniquement l'age ?
  5. >>> t[???]

...CORRECTION...

>>> e = "Alice;16 ans;Math;NSI;PC" >>> t = e.split(";") >>> t ['Alice', '16 ans', 'Math', 'NSI', 'PC'] >>> t[1] '16 ans'

7 - Convertir en tuple

Inutile de lire cette partie : cela fonctionne exactement comme avec list, sauf qu'on obtient un tuple.

7.1 - tupletuple avec tuple()

tuple vers tuple : peu d'utilité...

Utiliser tuple() sur un autre tuple permet d'en faire une copie peu profonde.

>>> tup = (1, 2, 4) # création d'un tableau >>> tup2 = tup >>> tup3 = tuple(tup) >>> tup2 (1, 2, 4) >>> tup3 (1, 2, 4)
7.2 - listtuple avec tuple()

list vers tuple

Utiliser tuple() sur un type list permet de faire une copie immuable des données du tuple muable1.

>>> t = [1, 2, 4] # création d'un tableau >>> tup = tuple(t) # tup est une copie immuable1 de t >>> t[0] = 100 # on modifie le contenu de la case 0 par 100 >>> t [100, 2, 4] # Modifié : normal >>> tup (1, 2, 4) # tup immuable de toutes manières !
7.3 - dicttuple avec tuple()

dict vers tuple

Identique au cas vers list, sauf qu'on obtient une donnée immuable.

>>> d = {'Alice':14, 'Bob':12} # création d'un dictionnaire >>> tup1 = tuple(d) # IMPLICITE : tup1 contient les clés de d >>> tup1 ('Alice', 'Bob') >>> tup2 = tuple(d.keys()) # EXPLICITE : tup2 contient les clés de d >>> tup2 ('Alice', 'Bob') >>> tup3 = tuple(d.values()) # EXPLICITE : tup3 contient les valeurs de d >>> tup3 (14, 12) >>> tup4 = tuple(d.items()) # EXPLICITE : tup4 contient les couples de d >>> t3 (('Alice', 14), ('Bob', 12))
7.4 strtuple avec tuple() : récupérer les caractères

Un string est un conteneur de caractères.

On peut donc les placer dans un autre conteneur, par exemple un tuple.

Pour cela, le plus simple est d'utiliser la fonction native tuple() qui tente de créer un tuple à partir des données fournies en entrée.

Récupérer les caractères dans un tableau

Il suffit d'utiliser la fonction native tuple().

>>> nom = "Merlin ou Toto l'asticot" >>> tup = tuple(nom) >>> tup ('M', 'e', 'r', 'l', 'i', 'n', ' ', 'o', 'u', ' ', 'T', 'o', 't', 'o', ' ', 'l', "'", 'a', 's', 't', 'i', 'c', 'o', 't')

8 - Convertir en dict

8.1 - dictdict avec dict()

dict vers dict : faire une copie rapide

Utiliser dict() sur un autre dictionnaire permet d'en faire une copie peu profonde.

>>> {'Alice': 14, 'Bob': 12} # création d'un dictonnaire >>> d2 = d # d2 n'est qu'un alias, un autre nom pour le même dictionnaire ! >>> d3 = dict(t) # d3 est une copie indépendante1 >>> d['Alice'] = 20 # on modifie le contenu de la case 'Alice' >>> d {'Alice': 20, 'Bob': 12} # Modifié : normal >>> d2 {'Alice': 20, 'Bob': 12} # Modifié : normal, c'est un alias de d ! >>> d3 {'Alice': 14, 'Bob': 12} # Non modifié : normal, c'est une copie.

Remarque 1 : la notion de copie indépendante n'est valable que si les éléments contenus sont des types simples.

8.2 - list|tuple|strdict avec dict() ?

On ne peut pas convertir n'importe quel type de list, tuple ou str en dictionnaire.

Nous verrons plus tard dans l'année qu'on peut convertir un type particulier de tableau en dictionnaire : on peut convertir un tableau de couple en dictionnaire.

9 - Convertir en str

9.1 - list|tuple|strstr avec str() ?

On peut convertir n'importe quel type de list, tuple ou dict en string.

Par contre, l'utilité directe est limitée. On pourrait l'utiliser pour sauvegarder un tel contenu dans un simple fichier-texte par exemple.

>>> str( [14, 12] ) "[14, 12]" >>> str( ('Alice', 12) ) "('Alice', 12)" >>> str( {'Alice': 14, 'Bob': 12} ) "{'Alice': 14, 'Bob': 12}"
9.2 - Créer un str avec join()

On peut convertir en str des cas particuliers d'autres types construits :

  • Des tableaux list dont les éléments sont des str;
  • Des n-uplets tuple dont les éléments sont des str;
  • Des dictionnaires dict dont les clés sont des str.

Pour cela, join() permet de concaténer les éléments ou les clés en les séparant par un string qu'on place devant join(). Voici des exemples d'utilisation :

>>> t = ["Ahah", "Bonbon", "Coucou"] >>> s = "---".join(t) >>> s 'Ahah---Bonbon---Coucou' >>> s = ";".join(t) >>> s 'Ahah;Bonbon;Coucou'
>>> d = {"Alice":14, "Bob":12, "Charlie":8} >>> s = "---".join(d) >>> s 'Alice---Bob---Charlie' >>> s = " ".join(d) >>> s 'Alice Bob Charlie'

10 - FAQ

J'ai entendu parlé de types composés ou structurés. C'est quoi ?

Des synonymes.

La notion de type construit est parfois dénommée également type structuré ou type composé.

On peut détruire une variable ?

Oui, on peut libérer la place mémoire attribuée à une variable. Pour cela, il faut utiliser le mot-clé del.

Exemple :

>>> a = 5 >>> a 5 >>> del a >>> a NameError: name 'a' is not defined

J'ai vu une notation bizarre : a += 1

Effectivement, on peut également utiliser une autre notation.

1 2
a = 10 a += 1

Cela donne ici le même résultat que ceci :

1 2
a = 10 a = a + 1

Attention, les deux façons de faire sont équivalentes ici, mais pas toujours. Evitez ces notations pour l'instant. De toutes manières, elles ne seront pas utilisées dans les sujets de NSI. Gardez la méthode n°2. C'est plus long mais c'est moins compliqué à comprendre de toutes manières.

Nous avons réussi à bien formaliser les choses en utilisant la console interactive. Mais nous ne faisons que taper des instructions qui s'exécutent immédiatement.

Nous avons vu comment stocker des informations dans des variables.

Il nous reste à voir comment stocker des instructions : créer un programme. De cette façon, nous n'aurons pas à taper les instructions. Elles seront enregistrées en mémoire.

Activité publiée le 17 09 2022
Dernière modification : 17 06 2024
Auteur : ows. h.