python index num

Identification

Infoforall

19 - Introduction aux index numériques


Nous allons voir aujourd'hui un nouveau type de stockage : les variables ayant un contenu accessible via un index numéroté.

Il s'agit de variables qui font référence à d'autres contenus et qu'on peut alors lire un élément à la fois.

Logiciel nécessaire pour l'activité : Thonny ou juste Python 3

Evaluation ✎ : questions 05-06-07-14

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

1 - Tableaux

Nous allons passer maintenant à une nouvelle structure de données qui ressemble par beaucoup d'aspects au string : le tableau.

Il possède deux différences notables :

  1. On peut y stocker d'autres choses que des caractères
  2. Il est mutable : on peut changer le contenu d'une case du tableau sans changer l'adresse mémoire de la variable-tableau
Tableau en informatique

Le mot tableau sera étudié plus en détail dans la partie DONNEES.

En informatique, un tableau est une structure de données ayant les propriétés suivantes :

  • La structure permet de stocker des données dans un nombre fixé de cases, défini lors de la déclaration initiale du tableau.
  • Chacune des cases contient le même type de données (soit des entiers sur 4 octets, soit des caractères, soit des entiers sur 2 octets, soit des floats sur 4 octets ...)

Voici deux exemples de tableaux 

Un tableau de caractéres de taille 3

Index Contenu
0 'A'
1 'B'
2 'C'

Un tableau de flottants de taille 4

Index Contenu
0 5.89
1 12.56
2 15.89
3 5.0

Nous allons voir maintenant comment un tableau s'utilise en Python.

1 - Déclaration d'un tableau avec des crochets [ ] en Python

Les éléments délimitateurs sont les crochets. Chaque élément du tableau est séparé des autres par une virgule.

Exemple

>>> table = ['a', 'b', 'c'] >>> table ['a', 'b', 'c'] >>> type(table) <class 'list'>

Comme vous pouvez le voir, le type natif de l'objet que nous utilisons pour gérer les tableaux statiques (arrays en anglais) dans Python se nomme list.

2 - Nombre d'éléments stockés avec len

On peut utiliser la fonction native len pour obtenir le nombre d'éléments (ici des caractères pour le premier cas et des floats pour le deuxième cas) stockés dans le tableau.

Exemple

>>> tableau = ['a', 'b', 'c'] >>> len(tableau) 3 >>> nbr = len(tableau) >>> nbr 3 >>> type(tableau) <class 'list'>
>>> tableau = [12.45, 5.0, 17.9, 4.32] >>> len(tableau) 4 >>> nbr = len(tableau) >>> nbr 4 >>> type(tableau) <class 'list'>

On remarquera bien que dans les deux cas, nous avons le type natif list : on ne trouve pas d'indication directe sur le type des données contenues dans le tableau.

La variable tableau désigne ici le conteneur, pas le contenu.

01° Créer un programme qui stocke le nombre de notes de l'élève A à partir de t_notes_A et le nombre d'élèves dans la classe à partir de t_eleves :

Tableau 1

t_notes_A = [15, 18, 8, 10, 12, 15, 20, 5, 12, 17, 12, 10, 13, 14] 

Phrase 2

t_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"] 

...CORRECTION...

1 2 3 4 5
t_notes_A = [15, 18, 8, 10, 12, 15, 20, 5, 12, 17, 12, 10, 13, 14] t_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"] nbr_notes = len(t_notes_A) nbr_eleves = len(t_eleves)

On obtient alors les réponses suivantes : 14 notes pour l'èlève A et 36 élèves au total.

>>> nbr_notes 14 >>> nbr_eleves 36
3 - Accès à l'un des éléments avec [index]

Pour accéder à l'un des éléments en particulier, on peut noter le nom de la variable-tableau suivi de crochets et y placer l'index du numéro voulu.

Exemple

>>> tableau = ['a', 'b', 'c'] >>> tableau[0] 'a' >>> tableau[1] 'b' >>> element_0 = tableau[0] >>> element_0 'a' >>> element_1 = tableau[1] >>> element_1 'b' >>> element_2 = tableau[2] >>> element_2 'c'

La correspondance index - élément donne ceci sur l'exemple

Index 0 1 2
Elément 'a' 'b' 'c'

On notera que l'index du premier élément porte le numéro d'index 0 et pas le numéro 1 !

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.

02° L'encodage ASCII des caractères fait correspondre un nombre à quelques caractères.

Afficher le caractère ayant l'index 65 en utilisant le tableau t_ascii.

t_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']

...CORRECTION...

1 2
t_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'] print(t_ascii[65])
4 - Lecture des éléments un à un via l'index (méthode classique par boucle numérique)

On peut aussi lire les éléments un par un en utilisant une boucle FOR couplée à la fonction len pour connaitre la valeur limite à placer pour l'indice d'incrémentation de la boucle.

Ainsi avec

 t_notes_A = [15, 18, 8, 10, 12, 15, 20, 5, 12, 17, 12, 10, 18, 4] 

Nous avons 14 éléments avec un index 0-1-2-3-4-5-6-7-8-9-10-11-12-13.

Index 0 1 2 3 4 5 6 7 8 9 10 11 12 13
Elément 15 18 8 10 12 15 20 5 12 17 12 10 18 4

Il faudrait donc utiliser for index in range(14):

Exemple

1 2 3 4 5
notes = [15, 18, 8, 10, 12, 15, 20, 5, 12, 17, 12, 10, 18, 4] nbr = len(notes) for index in range(nbr): print(notes[index])

Point important : on notera qu'on accéde à la valeur stockée dans la case numéro index avec notes[index]

Ce programme va afficher ceci dans la console :

15 18 8 10 12 15 20 5 12 17 12 10 18 4

Si on désire les voir s'afficher en les séparant par un tiret, on peut utiliser ceci :

1 2 3 4 5
notes = [15, 18, 8, 10, 12, 15, 20, 5, 12, 17, 12, 10, 18, 4] nbr = len(notes) for index in range(nbr): print(notes[index], end="-")

On obtient alors ceci

15-18-8-10-12-15-20-5-12-17-12-10-18-4-

03° Réaliser un court programme qui affiche les notes en notant "1er Trimestre : " pour les notes dont l'index est dans l'intervalle [0;9], c'est à dire de 0 inclus à 9 inclus, "2e Trimestre : " pour les notes dont l'index est dans l'intervalle [10;19] et "3e Trimestre : " pour les notes dont l'index est supérieur à 20.

notes = [15, 18, 8, 10, 12, 15, 20, 5, 12, 17, 12, 10, 18, 4]

Vous devriez donc obtenir quelque chose qui ressemble à ceci :

1er Trimestre : 15 1er Trimestre : 18 1er Trimestre : 8 1er Trimestre : 10 1er Trimestre : 12 1er Trimestre : 15 1er Trimestre : 20 1er Trimestre : 5 1er Trimestre : 12 1er Trimestre : 17 2e Trimestre : 12 2e Trimestre : 10 2e Trimestre : 18 2e Trimestre : 4

...CORRECTION...

1 2 3 4 5 6 7 8 9
notes = [15, 18, 8, 10, 12, 15, 20, 5, 12, 17, 12, 10, 18, 4] for index in range(len(notes)): if index < 10: print(f"1er Trimestre : {notes[index]}") elif index < 20: print(f"2e Trimestre : {notes[index]}") else: print(f"3e Trimestre : {notes[index]}")
5 - Lecture des éléments un à un (méthode nominative)

Cette gestion nominative d'itérer les éléments n'existe pas dans tous les langages.

1 2 3 4 5 6 7 8 9
notes = [15, 18, 8, 10, 12, 15, 20, 5, 12, 17, 12, 10, 18, 4] for element in notes: if element > 12: print(f"Bien : {element}") elif element < 8: print(f"Pas bien : {element}") else: print(f"Moyen : {element}")

Point important : ici, pas in range, juste le nom du tableau derrière le in : la variable de boucle contient directement l'élément contenu. On lit donc le contenu simplement à l'aide de element

Ce programme affiche "Bien", "Pas bien" ou "Moyen" devant chaque note sans avoir à passer par un index dans le code :

Bien : 15 Bien : 18 Moyen : 8 Moyen : 10 Moyen : 12 Bien : 15 Bien : 20 Pas bien : 5 Moyen : 12 Bien : 17 Moyen : 12 Moyen : 10 Bien : 18 Pas bien : 4
6- Modifier un tableau : mutabilité / muabilité des tableaux dans Python
>>> tableau = ['a', 'b', 'c'] >>> tableau ['a', 'b', 'c'] >>> tableau[0] = 'Z' >>> tableau ['Z', 'b', 'c']

On voit qu'on parvient à modifier le contenu de tableau sans avoir recours à une nouvelle affectation directe : aucun tableau = ....

L'affectation réalisée est la suivante : tableau[0] = 'Z'

On agit donc sur la case voulu en donnant le nom de la variable-tableau suivi de crochets contenant le numéro de la case à modifier.

Dans beaucoup de langages, les tableaux sont mutables (anglissisme, on dira muable en français) : cela veut dire qu'on peut modifier les contenus d'un tableau après sa création. On dit qu'on peut modifier l'état du tableau.

On peut donc modifier l'état du tableau après création, sans modifier l'identifiant-mémoire du tableau lui-même.

Avant la modification : tableau mène à l'id 12 et tableau[0] à l'id 40
Tableau mutable
Après la modification : tableau mène toujours à l'id 12 mais tableau[0] à l'id 48
Tableau mutable

Ainsi, si on veut multiplier par deux toutes les notes d'un tableau (spécial ProfQuiFaitUnDsTropDur), on pourra faire ceci :

1 2 3 4 5
notes = [15, 18, 8, 10, 12, 15, 20, 5, 12, 17, 12, 10, 18, 4] nbr = len(notes) for index in range(nbr): notes[index] = notes[index] * 2

Point important : on veut modifier, il faut donc connaître la position ou l'index de la case dans le tableau. Le FOR "nominatif" ne permet pas de faire cela : on ne fait que lire la case, sans possibilité de les changer.

✎ 04° Réaliser un court programme (sans fonction) pour les profs lunatiques : on transforme les notes contenus dans un tableau fourni en début de programme. Les notes initialement supérieures ou égales à 10 sont transformées en 20. Les notes inférieures à 10 sont transformées en 0.

Exemple AVANT / APRES :

[12, 10, 5, 2, 12]
[20, 20, 0, 0, 20]

Alors, for numérique ou for nominatif ?

Ca dépend des situations.

Situation 1 : modification du contenu ou position du contenu important : une seule solution

Vous avez besoin de connaître le numéro d'index de l'élément que vous examinez, il faut utiliser un for "numérique" :
for index in range(len(a)) avec

  • un accès au contenu de la case avec a[index]
  • une modification du contenu de la case avec a[index] = nouveau_contenu

Exemple : vous voulez mettre 0 dans toutes les cases (spécial Prof PasContent).

1 2 3 4 5
notes = [15, 18, 8, 10, 12, 15, 20, 5, 12, 17, 12, 10, 18, 4] nbr = len(notes) for index in range(nbr): notes[index] = 0

Situation 2 : deux solutions

Si vous n'avez pas besoin de connaître le numéro d'index de l'élément que vous examinez, vous pouvez utiliser la version que vous voulez.

  • for index in range(len(a)) avec un accès au contenu avec a[index]
  • for case in a avec un accès au contenu avec case

Jusqu'à présent, vous ne savez créer des tableaux qu'en déclaration : on note dans les crochets les valeurs voulues. Pour créer un tableau contenant les entiers de 1 à 3000, ca risque d'être long à taper...

7 - Déclaration de tableau par compréhension à partir d'un tableau initial

La déclaration d'un tableau par compréhension est celle qui consiste à formuler le contenu du tableau directement dans les crochets à l'aide d'une boucle for.

nouveau = [None for element in base]
>>> base = [1, 2, 5] >>> nouveau = [None for valeur in base] >>> nouveau [None, None, None]

En réalité, on peut faire mieux que mettre None dans chaque case : on peut indiquer le calcul à faire directement !

Si on veut un tableau contenant exactement le double du tableau précédent, on peut faire ceci :

nouveau = [element * 2 for element in base]
>>> base = [1, 2, 5] >>> nouveau = [valeur*2 for valeur in base] >>> nouveau [2, 4, 10]

C'est beaucoup plus simple à écrire qu'avec un for. En réalité, l'interpréteur Python réalise en arrière plan la boucle for.

✎ 05° Créer un tableau qui contient des valeurs 100 fois plus grandes que le tableau suivant :

>>> tab1 = [1, 2, 3, 5, 7, 11]
8 - Déclaration de tableau par compréhension avec un range

On peut également créer des tableaux contenant un nombre précis d'élements de façon assez facile : il suffit d'utliser range.

Exemple 1

>>> tableau = [0 for x in range(10)] >>> tableau [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

Cela veut dire qu'on place 0 dans une case pour chaque des valeurs x (qui valent 0 puis 1 puis 2 ... jusqu'à 9)

Exemple 2

>>> tableau = [x*10 for x in range(10)] >>> tableau [0, 10, 20, 30, 40, 50, 60, 70, 80, 90]

Cette fois, la variable de boucle x va varier de 0 à 9 et pour chacune des valeurs qu'elle prend, on place 10*x dans une nouvelle case du nouveau tableau.

Exemple 3

>>> import random >>> tableau = [random.randint(1,100) for x in range(10)] >>> tableau [42, 41, 96, 35, 58, 94, 16, 21, 84, 51]

Cette fois, on crée 10 cases dans lesquelles on place un nombre aléatoire entre 1 et 100.

✎ 06° Créer par compréhension un tableau de 20 éléments contenant des nombres aléatoires compris entre 20 et 50.

✎ 07° Créer par compréhension un tableau de 500 éléments contenant 0.

On peut même faire mieux : on peut inclure des tests ou des fonctions dans la construction.

Premier exemple : on crée un tableau de 50 éléments compris entre 0 et 20. On crée un second tableau à partir du premier : on ne garde que les nombres supérieurs ou égaux à 10.

>>> import random >>> tableau = [random.randint(0,20) for valeur in range(50)] >>> tableau_2 = [note for note in tableau if note >= 10] >>> tableau [12, 8, 1, 3, 3, 17, 8, 2, 2, 10, 15, 3, 16, 13, 5, 18, 12, 15, 19, 10, 9, 14, 0, 15, 11, 6, 11, 1, 10, 6, 17, 3, 17, 10, 9, 8, 1, 9, 7, 12, 15, 10, 15, 15, 9, 8, 18, 8, 9, 6] >>> tableau_2 [12, 17, 10, 15, 16, 13, 18, 12, 15, 19, 10, 14, 15, 11, 11, 10, 17, 17, 10, 12, 15, 10, 15, 15, 18]

On peut même utiliser des fonctions pour déterminer la valeur à placer lors de la création par compréhension. Imaginons qu'on dispose de cette fonction en mémoire :

1 2 3 4 5
def pas_plus(valeur, seuil): '''Fonction qui renvoie la valeur ou le seuil si la valeur est supérieure au seuil''' if valeur > seuil: return seuil return valeur
>>> import random >>> tableau = [pas_plus(random.randint(0,20), 15) for valeur in range(10)] >>> tableau [14, 15, 7, 14, 11, 1, 13, 12, 15, 1]

On obtient bien un tableau de 10 éléments sans qu'aucun élément ne soit plus grand que 15.

C'est tout pour le premier contact avec les tableaux, qu'on implémente en Python à l'aide des list.

Pour informations, sachez qu'une list Python n'a pas nécessairement besoin que les éléments qu'on y place soient tous de même nature. Mais comme nous les utiliserons comme des tableaux (présents dans tous les langages), nous nous limiterons au cas d'éléments de même nature.

On pourrait créer une list Python contenant ceci :
exemple = [1, 1.55, 'bonjour']
Mais dans ce cas, nous ne dirons pas qu'exemple est un tableau.

2 - P-uplets

Dernière structure de données que nous allons survoler ici : le p-uplets de valeurs.

Un p-uplet est une structure ordonnée :

  • contenant p éléments
  • permettant de stocker des données de natures différentes (contrairement aux strings ou aux tableaux)
  • indexable par un numéro (comme les strings et les tableaux)

Comme il s'agit d'une structure non mutable en Python, on l'utilise beaucoup lorsqu'on veut transmettre des données sans qu'elles ne puissent être modifiées "par accident". Contrairement aux tableaux, modifier les éléments d'un tuple nécessite d'écraser volontairement la variable avec une nouvelle affectation.

1 - Déclaration d'un p-uplet avec des parenthèses ( ) en Python

En anglais, on dira tuple.

Les éléments délimitateurs sont les parenthèses. Chaque élément du p-uplet est séparé des autres par une virgule.

Exemple avec un p-uplet contenant le nom du produit, le nombre en stock et le prix à l'unité.

>>> exemple = ('Ananas', 60, 2.20) >>> exemple ('Ananas', 60, 2.20) >>> type(exemple) <class 'tuple'>

Attention, si vous voulez créer un p-uplet ne contenant qu'un seul élément, il faudra placer une virgule après le premier élément. Sinon, l'interpréteur Python croira qu'il s'agit juste de parenthèses.

Exemple à ne pas faire si vous voulez un tuple

>>> exemple = ('Ananas') >>> exemple 'Ananas' >>> type(exemple) <class 'str'>

Exemple à faire si vous voulez un tuple

>>> exemple = ('Ananas' ,) >>> exemple ('Ananas',) >>> type(exemple) <class 'tuple'>
2 - Nombre d'éléments stockés avec len

On peut utiliser la fonction native len pour obtenir le nombre d'éléments stockés dans le p-uplet.

Exemple

>>> exemple = ('Ananas', 60, 2.20) >>> len(exemple) 3

On peut nommer

  • couple ou doublet un p-uplet de 2 éléments
  • triplet un p-uplet de 3 éléments
  • quadruplet un p-uplet de 4 éléments
  • quintuplet un p-uplet de 5 éléments
  • ...
3 - Accès à l'un des éléments avec [index]

Pour accéder à l'un des éléments en particulier, on peut noter le nom de la variable suivi de crochets et y placer l'index du numéro voulu.

Exemple

>>> exemple = ('Ananas', 60, 2.20) >>> exemple[0] 'Ananas' >>> element_0 = exemple[0] >>> element_0 'Ananas' >>> element_1 = exemple[1] >>> element_1 60 >>> element_2 = exemple[2] >>> element_2 2.2

La correspondance index - élément donne ceci sur l'exemple

Index 0 1 2
Elément 'Ananas' 60 2.2

On notera que l'index du premier élément porte le numéro d'index 0 et pas le numéro 1 !

4 - Lecture des éléments un à un par l'index (méthode classique avec boucle numérique)

On peut aussi lire les éléments un par un en utilisant une boucle FOR couplée à la fonction len pour connaitre la valeur limite à placer pour l'indice d'incrémentation de la boucle.

Ainsi avec

 t_notes_A = (15, 18, 8, 10, 12, 15, 20, 5, 12, 17, 12, 10, 18, 4) 

Nous avons 14 éléments avec un index 0-1-2-3-4-5-6-7-8-9-10-11-12-13.

Index 0 1 2 3 4 5 6 7 8 9 10 11 12 13
Elément 15 18 8 10 12 15 20 5 12 17 12 10 18 4

Il faudrait donc utiliser for index in range(14):

Exemple

1 2 3 4 5
notes = (15, 18, 8, 10, 12, 15, 20, 5, 12, 17, 12, 10, 18, 4) nbr = len(notes) for index in range(nbr): print(notes[index])
Point important : on notera qu'on accéde à la valeur stockée dans la case numéro index avec notes[index]

Ce programme va afficher ceci dans la console :

15 18 8 10 12 15 20 5 12 17 12 10 18 4

On remarquera qu'il s'agit des mêmes exemples qu'avec les tableaux. L'unique différence vient ici de l'utilisation de parenthèses plutôt que de crochets lors de la déclaration.

5 - Lecture des éléments un à un (méthode nominative)

Cette gestion nominative d'itérer les éléments n'existe pas dans tous les langages.

1 2 3 4 5 6 7 8 9
notes = (15, 18, 8, 10, 12, 15, 20, 5, 12, 17, 12, 10, 18, 4) for element in notes: if element > 12: print(f"Bien : {element}") elif element < 8: print(f"Pas bien : {element}") else: print(f"Moyen : {element}")

Ce programme affiche "Bien", "Pas bien" ou "Moyen" devant chaque note sans avoir à passer par un index dans le code :

Bien : 15 Bien : 18 Moyen : 8 Moyen : 10 Moyen : 12 Bien : 15 Bien : 20 Pas bien : 5 Moyen : 12 Bien : 17 Moyen : 12 Moyen : 10 Bien : 18 Pas bien : 4
6 - Non mutabilité / Immuabilité des tuples EN PYTHON

En Python, les tuples sont non mutables (anglissisme) ou immuables (en français véritable) : cela veut dire qu'on ne peut pas modifier le contenu après sa création. On dit qu'on ne peut pas modifier l'état du tuple placé en mémoire.

>>> produit = ('Ananas', 60, 2.2) >>> produit[1] = 50 TypeError: 'tuple' object does not support item assignment

Nous allons voir maintenant les utilisations courantes des tuples 

  • Retour de plusieurs données (qu'on ne veut pas pouvoir modiifier par inadvertance) par une fonction
  • Volonté de transmettre une donnée non mutable / immuable

Volonté de transmettre une donnée non mutable / immuable

Voici un programme qui possède une fiche d'enregistrement sur un produit : son nom ('Jeu vidéo de la mort qui tue'), le nombre vendu (103) et la marge de bénéfice sur chaque vente (20.3).

1 2 3 4 5 6 7 8 9 10 11 12 13 14
def fournir_fiche_marge(fiche_recue): '''Fonction qui renvoie un tuple-enregistrement contenant le nom du produit et le bénéfice sur ce produit (nbr*marge) ::param fiche_recue(tuple (str, int, float)) :: le nom du produit, nombre vendu et marge sur chaque vente ::return (tuple (str, float)) :: tuple contenant le nom du produit et la marge qu'il a ramené >>> fournir_fiche_marge(("Voiture électrique", 100, 5.0)) ('Voiture électrique', 500.0) ''' return ('vide', 0) fiche_produit_1 = ('Jeu vidéo de la mort qui tue', 103, 20.3) fiche_marge = fournir_fiche_marge(fiche_produit_1)

08° Lors de l'appel de la ligne 13, que va contenir le paramètre fiche_recue de la fonction ? Que contient alors fiche_recue[2] ?

...CORRECTION...

L'argument envoyé étant fiche_produit_1, on va avoir fiche_recue = fiche_produit_1 = ('Jeu vidéo de la mort qui tue', 103, 20.3)

On voit que fiche_recue[0] va donc être évalué 'Jeu vidéo de la mort qui tue'.

On voit que fiche_recue[2] va donc être évalué à 20.3.

09° Modifier la fonction pour qu'elle fasse le travail qu'on lui demande de faire : calculer le bénéfice sur la vente du produit et renvoyer un tuple contenant les bonnes informations (voir les lignes 7/8 de la documentation).

Par exemple, on envoie la fiche suivante à la fonction :

fiche_produit_1 = ('Jeu vidéo de la mort qui tue', 10, 200.0)

La fonction va calculer 10*200.0 et renvoyer un tuple ('Jeu vidéo de la mort qui tue', 2000.0)

...CORRECTION...

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
def fournir_fiche_marge(fiche_recue): '''Fonction qui renvoie un tuple-enregistrement contenant le nom du produit et le bénéfice sur ce produit (nbr*marge) ::param fiche_recue(str,int,float) :: le nom du produit, nombre vendu et marge sur chaque vente ::return (str, float) :: tuple contenant le nom du produit et la marge qu'il a ramené >>> fournir_fiche_marge(("Voiture électrique", 100, 5.0)) ('Voiture électrique', 500.0) ''' nom = fiche_recue[0] marge_totale = fiche_recue[1] * fiche_recue[2] return (nom, marge_totale) fiche_produit_1 = ('Jeu vidéo de la mort qui tue', 103, 20.3) fiche_marge = fournir_fiche_marge(fiche_produit_1)

10° Après exécution du programme (avec la fonction correctement réalisée), que devrait afficher la console si on tape ceci ?

>>> fiche_marge[1]

Plus tard, quelqu'un tape l'instruction ci-dessous par erreur dans la console : alors qu'il voulait voir la valeur, il tente donc d'affecter une nouvelle valeur. Que va-t-il se passer ? La donnée est-elle plus sécurisée qu'avec un tableau ?

>>> fiche_marge[1] = 0

...CORRECTION...

La fonction devrait avoir calculé la marge qui vaut 103*20.3, soit 2090.9.

Par contre, l'affectation provoque une erreur : le tuple est une structure non mutable en Python.

Retour de plusieurs données par une fonction

Autre gros intérêt des tuples en Python : on peut faire semblant d'avoir une fonction qui renvoie plusieurs réponses !

Imaginons qu'on veuille créer une fonction qui renvoie les coordonnées x et y d'une tortue du module turtle ainsi que son angle. Pas possible  3 réponses à fournir.

Voici la version TUPLE EXPLICITE : on voit EXPLICITEMENT les parenthèses ligne 7 qui montrent qu'on renvoie un TUPLE

1 2 3 4 5 6 7
import turtle as trt def infos(feutre): x = feutre.xcor() y = feutre.ycor() angle = feutre.heading() return (x,y,angle)

11° Utiliser le code suivant pour vous convaincre que la fonction renvoie bien un tuple contenant 3 informations. Le mieux est certainement de visualiser à la fois la console de Thonny et l'interface graphique Turtle.

1 2 3 4 5 6 7
import turtle as trt def infos(feutre): x = feutre.xcor() y = feutre.ycor() angle = feutre.heading() return (x,y,angle)

Vous allez voir que la première valeur est bien la coordonnée sur l'abscisse, la deuxième valeur la coordonnée sur l'ordonnée et la troisième l'angle que fait la tortue.

>>> crayon = trt.Turtle() >>> infos(crayon) (0.0, 0.0, 0.0) >>> crayon.forward(100) >>> infos(crayon) (100.0, 0.0, 0.0) >>> crayon.left(90) >>> infos(crayon) (100.0, 0.0, 90.0) >>> crayon.forward(50) >>> infos(crayon) (100.0, 50.0, 90.0)

Pour l'instant, renvoyer un tuple ou un tableau reviendrait au même.

On peut écrire ceci avec un tuple ou un tableau puisqu'on reçoit une réponse composée d'un ensemble de trois valeurs : la première et la deuxième sont les coordonnées et le dernier est l'angle :

>>> crayon = trt.Turtle() >>> reponse = infos(crayon) >>> x = reponse[0] >>> y = reponse[1] >>> a = reponse[2]

Ou même :

>>> crayon = trt.Turtle() >>> (x, y, a) = infos(crayon)

L'intérêt de renvoyer un tuple plutôt qu'un tableau ? On peut noter ceci dans la plupart des langages :

>>> crayon = trt.Turtle() >>> x, y, a = infos(crayon)

Du coup, on récupére directement des variables x, y et a correctement remplis.

On peut également récupérer directement les données d'une fonction renvoyant un tuple : il suffit de stocker le résultat dans un ensemble de variables, plutôt que dans un tuple directement.

12° La fonction renvoie-t-elle vraiment trois valeurs différentes ?

...CORRECTION...

Non : la fonction renvoie un TUPLE qui contient 3 valeurs contenues au index 0, 1 et 2.

L'interpréteur est codé de telle façon qu'écrire ceci (c'est court et explicite) :

>>> crayon = trt.Turtle() >>> x, y, a = infos(crayon)

revient à écrire cela (c'est plus long et beaucoup moins clair):

>>> crayon = trt.Turtle() >>> reponse = infos(crayon) >>> x = reponse[0] >>> y = reponse[1] >>> a = reponse[2]

3 - transformation de l'un en l'autre

Nous venons de voir que les structures de données ont des avantages et des inconvénients.

En Python, si on veut qu'une fonction puisse modifier les données stockées, il faut utiliser un tableau par exemple.

Si par contre, on veut juste fournir des valeurs, autant utiliser un tuple qui évitera ainsi que quelqu'un les modifie par erreur.

Mais comment passer de l'un à l'autre ?

En utilisant les fonctions natives permettant de le faire :

  • str tente de transformer les données fournies en une string
  • list tente de transformer les données fournies en un tableau (list)
  • tuple tente de transformer les données fournies en un p-uplet (tuple)

13° Exécuter les commandes suivantes dans la console pour comprendre l'action de ces trois fonctions

En partant d'un string

>>> chaine = "abc" >>> chaine 'abc' >>> tableau = list(chaine) >>> tableau ['a', 'b', 'c'] >>> puplet = tuple(chaine) >>> puplet ('a', 'b', 'c')

En partant d'un tableau

>>> tableau = ['a','b','c'] ['a', 'b', 'c'] >>> chaine = str(tableau) >>> chaine "['a', 'b', 'c']" >>> puplet = tuple(tableau) >>> puplet ('a', 'b', 'c')

En partant d'un tuple

>>> puplet = ('a','b','c') ('a', 'b', 'c') >>> chaine = str(puplet) >>> chaine "('a', 'b', 'c')" >>> tableau = list(puplet) >>> tableau ['a', 'b', 'c']

Une dernière remarque pour la fin

Comment trouver le nombre de mots dans une phrase ?

En utilisant simplement une fonction maison ou en utilisant la méthode split des strings.

Cette méthode crée une liste à partir d'un string. Comment ? En divisant le string à l'aide d'un élément délimitateur. Par défaut, il s'agit de l'espace.

>>> phrase = "Voici un exemple de phrase, il permet de compter les mots." >>> mots = phrase.split() >>> mots ['Voici', 'un', 'exemple', 'de', 'phrase,', 'il', 'permet', 'de', 'compter', 'les', 'mots.'] >>> nbr_mots = len(mots) >>> nbr_mots 11

Et du coup, nous pouvons en faire une fonction. Une tâche = une fonction.

1 2 3 4
def compter_mots(phrase) : '''Renvoie le nombre de mots dans le string phrase''' mots = phrase.split() return len(mots)

Bien entendu, il reste encore quelques détails à régler, comme supprimer les points et les virgules. Mais il faut bien que vous fassiez deux trois choses pendant vos projets !

4 - Appartenance

Une action assez courante sur les structures de données organisées par index est de savoir si un élément appartient à la structure.

Voici une fonction appartient qui permet de vérifier que l'élément x est contenu dans un tableau par exemple :

1 2 3 4 5 6
def appartient(x, tableau): '''Fonction booléenne : True si x appartient à tableau. False sinon''' for index in range(len(tableau)): if tableau[index] == x: return True return False

Comme on ne fait que lire la case, on peut utiliser également cette version :

1 2 3 4 5 6
def appartient(x, tableau): '''Fonction booléenne : True si x appartient à tableau. False sinon''' for element in tableau: if element == x: return True return False

Mais on peut faire encore plus simple car un tel mécanisme existe déjà dans Python. On utilise le mot-clé in.

1 2 3
def appartient(x, tableau): '''Fonction booléenne : True si x appartient à tableau. False sinon''' return x in tableau

L'expression x in tableau est donc une expression booléenne : elle est évaluée à True si x est bien un élément du tableau.

Le plus beau, c'est que cela fonctionne avec les tableaux, les tuples et les strings.

>>> tableau = [12, 5, 18] >>> 5 in tableau True >>> 6 in tableau False >>> nuplet = ("alors", "ça", "va", "?") >>> "ça" in nuplet True >>> "ca" in nuplet False >>> chaine = "Alors, ça va ?" >>> "Alors" in chaine True >>> "Bonjour" in chaine False

✎ 14° Créer une fonction qui permet de savoir si une séquence ADN particulière (une simple chaîne de caractères pour l'informaticien) se trouve dans ADN (une autre chaîne de caractères pour l'informaticien). Tester alors votre fonction avec la recherche de "TATTTAAATTATTTC" dans la chaîne suivante. Vous devriez trouver qu'elle est présente. Mais à la main, ca risque d'être long...

ADN = "CAACTCCTAAGCCAGTGCCAGAAGAGCCAAGGACAGGTACGGCTGTCATCACTTAGACCTCACCCTGTGGAGCCACACCCTAGGGTTGGCCAATCTACTCCCAGGAGCAGGGAGGGCAGGAGCCAGGGCTGGGCATAAAAGTCAGGGCAGAGCCATCTATTGCTTACATTTGCTTCTGACACAACTGTGTTCACTAGCAACCTCAAACAGACACCATGGTGCACCTGACTCCTGAGGAGAAGTCTGCCGTTACTGCCCTGTGGGGCAAGGTGAACGTGGATGAAGTTGGTGGTGAGGCCCTGGGCAGGTTGGTATCAAGGTTACAAGACAGGTTTAAGGAGACCAATAGAAACTGGGCATGTGGAGACAGAGAAGACTCTTGGGTTTCTGATAGGCACTGACTCTCTCTGCCTATTGGTCTATTTTCCCACCCTTAGGCTGCTGGTGGTCTACCCTTGGACCCAGAGGTTCTTTGAGTCCTTTGGGGATCTGTCCACTCCTGATGCTGTTATGGGCAACCCTAAGGTGAAGGCTCATGGCAAGAAAGTGCTCGGTGCCTTTAGTGATGGCCTGGCTCACCTGGACAACCTCAAGGGCACCTTTGCCACACTGAGTGAGCTGCACTGTGACAAGCTGCACGTGGATCCTGAGAACTTCAGGGTGAGTCTATGGGACCCTTGATGTTTTCTTTCCCCTTCTTTTCTATGGTTAAGTTCATGTCATAGGAAGGGGAGAAGTAACAGGGTACAGTTTAGAATGGGAAACAGACGAATGATTGCATCAGTGTGGAAGTCTCAGGATCGTTTTAGTTTCTTTTATTTGCTGTTCATAACAATTGTTTTCTTTTGTTTAATTCTTGCTTTCTTTTTTTTTCTTCTCCGCAATTTTTACTATTATACTTAATGCCTTAACATTGTGTATAACAAAAGGAAATATCTCTGAGATACATTAAGTAACTTAAAAAAAAACTTTACACAGTCTGCCTAGTACATTACTATTTGGAATATATGTGTGCTTATTTGCATATTCATAATCTCCCTACTTTATTTTCTTTTATTTTTAATTGATACATAATCATTATACATATTTATGGGTTAAAGTGTAATGTTTTAATATGTGTACACATATTGACCAAATCAGGGTAATTTTGCATTTGTAATTTTAAAAAATGCTTTCTTCTTTTAATATACTTTTTTGTTTATCTTATTTCTAATACTTTCCCTAATCTCTTTCTTTCAGGGCAATAATGATACAATGTATCATGCCTCTTTGCACCATTCTAAAGAATAACAGTGATAATTTCTGGGTTAAGGCAATAGCAATATTTCTGCATATAAATATTTCTGCATATAAATTGTAACTGATGTAAGAGGTTTCATATTGCTAATAGCAGCTACAATCCAGCTACCATTCTGCTTTTATTTTATGGTTGGGATAAGGCTGGATTATTCTGAGTCCAAGCTAGGCCCTTTTGCTAATCATGTTCATACCTCTTATCTTCCTCCCACAGCTCCTGGGCAACGTGCTGGTCTGTGTGCTGGCCCATCACTTTGGCAAAGAATTCACCCCACCAGTGCAGGCTGCCTATCAGAAAGTGGTGGCTGGTGTGGCTAATGCCCTGGCCCACAAGTATCACTAAGCTCGCTTTCTTGCTGTCCAATTTCTATTAAAGGTTCCTTTGTTCCCTAAGTCCAACTACTAAACTGGGGGATATTATGAAGGGCCTTGAGCATCTGGATTCTGCCTAATAAAAAACATTTATTTTCATTGCAATGATGTATTTAAATTATTTCTGAATATTTTACTAAAAAGGGAATGTGGGAGGTCAGTG"

5 - FAQ

Rien pour l'instant

6 -

Nous avons vu  

  • Les fonctions
  • Les instructions conditionnelles if elif else
  • Les boucles bornées for
  • Les boucles non bornées while
  • Strings, tuples et tableaux

Nous sommes maintenant assez armés pour réaliser de vrais programmes gérant les données de façon automatisée.

Et partir sur les premiers vrais projets de groupe.

Des informations supplémentaires dans la partie FICHES, dont

Activité publiée le 01 11 2019
Dernière modification : 03 12 2020
Auteur : ows. h.