Listes — beaucoup de valeurs sous un seul nom
Conserver autant de valeurs que vous voulez sous un seul nom, y accéder avec un index et un slice, les méthodes qui modifient une liste, et le piège de deux noms qui finissent attachés à la même liste.
Comment voulez-vous apprendre ?
Le problème que nous résolvons
Une boutique doit conserver les prix de trois produits. Avec tout ce que vous avez appris jusqu'ici, il n'y a qu'une seule façon de le faire :
price_1 = 15
price_2 = 60
price_3 = 850
print(price_1 + price_2 + price_3)925Maintenant la question : et quarante produits ? Quarante variables. Et une ligne d'arithmétique avec quarante éléments dedans. Et quand la boutique commence à vendre quelque chose de nouveau, il faut aller dans le code et inventer une autre variable.
Le problème n'est pas seulement la frappe, c'est la forme. Pour Python, price_1, price_2 et price_3 sont trois noms complètement sans rapport — aussi sans rapport que name et age. Vous savez que ce sont trois exemples de la même chose. Il nous manque simplement un moyen d'écrire « beaucoup de la même chose » en code.
Une liste est ce moyen. Un seul nom, autant de valeurs que vous voulez en dessous, dans l'ordre.
À la fin de ce chapitre, vous pourrez
- Construire une liste et y accéder avec un index et un slice
- Modifier une liste avec
append,insert,removeetpop - Expliquer pourquoi une liste peut être modifiée alors qu'un morceau de texte ne peut pas
- Reconnaître et éviter
b = a, qui laisse deux noms attachés à une liste - Lire un
IndexErroret unValueErroret dire ce qui s'est mal passé
Prérequis : Les boucles for et range.
Créer une liste
Des crochets, avec les valeurs séparées par des virgules :
prices = [15, 60, 850]
print(prices)
print(len(prices))[15, 60, 850]
3len() fonctionne ici exactement comme sur le texte — trois valeurs, donc 3.
L'affichage montre toute la liste, crochets compris. Ce n'est pas pour qu'un utilisateur le lise, c'est pour que vous compreniez : [15, 60, 850] vous dit que c'est une liste, et non 925.
Accéder aux éléments
L'indexation fonctionne exactement comme pour les chaînes — on compte à partir de zéro, et depuis la fin avec les négatifs :
prices = [15, 60, 850]
print(prices[0])
print(prices[-1])
print(prices[1:])15
850
[60, 850]Les trois lignes sont les règles du chapitre six, inchangées. Une différence mérite qu'on la remarque : prices[0] renvoie un nombre, tandis que prices[1:] renvoie une liste. Un slice renvoie toujours le même type de chose que celui dont il a été découpé, jamais un morceau seul.
Et voici la vraie différence : une liste peut être modifiée
Dans le chapitre six, nous avons vu qu'un caractère à l'intérieur d'un texte ne peut pas être remplacé :
name = "rafi"
name[0] = "R"TypeError: 'str' object does not support item assignmentLa même ligne fonctionne sur une liste :
prices = [15, 60, 850]
prices[0] = 20
print(prices)[20, 60, 850]Aucune nouvelle liste n'a été créée — c'est cette liste qui a changé. C'est la propriété la plus importante d'une liste, et le piège de la fin de ce chapitre en découle directement.
Les mots pour cela : un texte est immuable, une liste est modifiable.
Ajouter et retirer
stock = ["pen", "notebook"]
stock.append("bag")
stock.insert(1, "eraser")
print(stock)
stock.remove("pen")
print(stock)
last = stock.pop()
print(last)
print(stock)['pen', 'eraser', 'notebook', 'bag']
['eraser', 'notebook', 'bag']
bag
['eraser', 'notebook']Quatre méthodes, quatre rôles différents :
append(x)— ajoute à la fininsert(i, x)— le place à la positioni, en décalant tout ce qui suit vers la droiteremove(x)— trouve le premier élément ayant cette valeur et le supprimepop()— supprime le dernier élément et vous le rend
La différence entre ces deux dernières est là où se loge l'essentiel de la confusion : remove veut savoir quoi supprimer, pop veut savoir depuis où. Et pop vous donne la chose qu'il a supprimée ; remove non.
Ces méthodes ne renvoient pas la liste. Avec le texte, vous deviez conserver le résultat dename.upper(), car il construisait un nouveau texte et vous le rendait. Les listes fonctionnent à l'inverse :appendmodifie la liste elle-même et renvoieNone.
Ce qui en fait une erreur classique :
stock = ["pen", "notebook"]
stock = stock.append("bag")
print(stock)NoneLa liste a disparu. Écrivez stock.append("bag"), et non stock = stock.append("bag").
Chercher et parcourir
stock = ["pen", "notebook", "bag"]
print("pen" in stock)
print("chair" in stock)
for item in stock:
print(item.upper())True
False
PEN
NOTEBOOK
BAGin cherchait dans le texte, et il cherche aussi dans une liste — le même mot qui fait le même travail.
Et for item in stock parcourt les valeurs une à la fois. Remarquez qu'il n'y a ni range ni arithmétique d'index, exactement comme quand nous parcourions les caractères d'un mot dans le chapitre onze.
Quand vous avez besoin de la position et de la valeur, enumerate :
stock = ["pen", "notebook"]
for position, item in enumerate(stock, start=1):
print(position, item)1 pen
2 notebookSans start=1, le compte commence à zéro. Une liste montrée à une personne commence généralement à un.
Le piège qui prend tout le monde
Dans le chapitre quatre, nous avons vu ceci :
a = 3
b = a
b = b + 1
print(a, b)3 4b a reçu une valeur et ne dépendait pas de a. Maintenant, faites la même chose avec une liste :
a = [1, 2, 3]
b = a
b.append(4)
print(a)
print(b)[1, 2, 3, 4]
[1, 2, 3, 4]b a été modifié, et a aussi.
La raison ne contredit pas la règle précédente, elle est la règle précédente. Sur la ligne b = a, b a reçu exactement ce que a contenait — et ce que a contenait était l'emplacement de la liste, pas une copie de la liste. Les deux noms pointent donc maintenant vers la même liste. b.append(4) a modifié cette unique liste, et les deux noms montrent le même changement.
Vous ne voyez jamais cela avec les nombres, parce que b = b + 1 ne modifie pas l'ancien nombre — il en crée un nouveau et le met dans b. Les nombres sont sûrs précisément parce qu'ils ne peuvent pas être modifiés. Les listes, elles, peuvent être modifiées, donc elles ne sont pas sûres.
Si vous voulez une copie séparée, il faut la demander :
a = [1, 2, 3]
b = a.copy()
b.append(4)
print(a)
print(b)[1, 2, 3]
[1, 2, 3, 4]Quand faire attention. Chaque fois que vous mettez une liste sous un second nom, ou que vous passez une liste à une fonction (chapitre dix-neuf), demandez-vous une fois : est-ce que je veux modifier celle-ci, ou est-ce que je veux une copie ? Ceux qui ne se posent jamais cette question passent des jours à traquer des bugs qui se lisent « mais je n'ai rien changé ici ».
Un exemple complet
shopping.py :
# A shopping list, built up and then summarised
items = []
items.append("pen")
items.append("notebook")
items.append("bag")
items.insert(0, "eraser")
print("List :", items)
print("Count :", len(items))
print("First :", items[0])
print("Last :", items[-1])
print("Has bag :", "bag" in items)
items.remove("pen")
dropped = items.pop()
print()
print("After removing 'pen' and popping the last one:")
print("List :", items)
print("Dropped :", dropped)
print("Count :", len(items))
print()
print("Numbered:")
for position, item in enumerate(items, start=1):
print(f" {position}. {item}")List : ['eraser', 'pen', 'notebook', 'bag']
Count : 4
First : eraser
Last : bag
Has bag : True
After removing 'pen' and popping the last one:
List : ['eraser', 'notebook']
Dropped : bag
Count : 2
Numbered:
1. eraser
2. notebookTrois choses à remarquer.
Cela commence par une liste vide. La ligne items = [] fait le même travail qu'un accumulateur à l'extérieur d'une boucle dans le chapitre dix — là où se trouvait total = 0, se trouve maintenant []. Il vous faut un endroit où collecter avant de commencer à collecter.
insert(0, "eraser") l'a placé au tout début, donc eraser est en premier dans la liste affichée. L'ordre dans lequel les choses ont été ajoutées n'est pas l'ordre dans lequel elles se retrouvent.
pop() a rendu ce qu'il a supprimé, donc dropped contient bag. remove("pen") n'a rien renvoyé, le pen supprimé a donc simplement disparu.
En cas de problème
IndexError: list index out of range Un index au-delà du nombre de valeurs dans la liste. Dans une liste de trois, les index valides sont 0, 1, 2 — il n'y a pas de prices[3]. Pour la dernière valeur, prices[-1] est la façon la plus sûre de l'écrire, car il n'a pas besoin de connaître la longueur.
ValueError: list.remove(x): x not in list La valeur que vous avez demandé à supprimer n'est pas là. Vérifiez d'abord avec if x in stock:, ou utilisez try du chapitre vingt-quatre.
AttributeError: 'NoneType' object has no attribute 'append' Une ligne précédente a dit stock = stock.append(...), donc stock vaut maintenant None. Ne conservez pas le résultat — stock.append(...) tout seul est l'opération complète.
J'ai modifié une liste et une autre a changé aussi Deux noms sont attachés à une liste. Écrivez b = a.copy() plutôt que b = a.
Je supprime à l'intérieur d'une boucle et des éléments sont sautés
numbers = [1, 2, 2, 3, 4]
for n in numbers:
if n % 2 == 0:
numbers.remove(n)
print(numbers)[1, 2, 3]Un 2 a survécu. Raccourcir la liste que vous parcourez met le comptage de Python en décalage avec les positions de la liste, donc certaines valeurs sont sautées. Le correctif n'est pas de supprimer, mais de collecter ce que vous voulez garder dans une nouvelle liste.
numbers = [1, 2, 2, 3, 4]
kept = []
for n in numbers:
if n % 2 != 0:
kept.append(n)
print(kept)[1, 3]J'ai nommé une variable list et maintenant list(...) ne fonctionne pas list est l'un des noms intégrés de Python. Utilisez un nom explicite — items, prices, names.
Étape 4 sur 6 — Prédire
Vérifiez votre compréhension
Le résultat de append est réassigné à stock. Que s'affiche-t-il ?
stock = ["pen", "notebook"]
stock = stock.append("bag")
print(stock)- ANone
- B['pen', 'notebook', 'bag']
- C['bag']
- DUne `AttributeError`
Seul b a été modifié. Que s'affichent les deux lignes ?
a = [1, 2, 3]
b = a
b.append(4)
print(a)
print(b)- A[1, 2, 3] [4]
- B[1, 2, 3] [1, 2, 3, 4]
- C[1, 2, 3, 4] [1, 2, 3]
- D[1, 2, 3, 4] [1, 2, 3, 4]
La liste contient trois valeurs et on demande l'index trois. Que se passe-t-il ?
prices = [15, 60, 850]
print(prices[3])- AUne liste vide
- BUn `IndexError` — avec trois valeurs, les index valides sont `0`, `1`, `2`
- CNone
- D850 — la dernière valeur
Répondre nécessite un compte
Connectez-vous pour vérifier vos réponses
Les questions sont ci-dessus, et les résoudre de tête est ce qui compte vraiment. Connectez-vous pour voir les réponses, les explications et les indices à trois niveaux.
À vous de jouer
Écrivez un fichier appelé marks.py contenant une liste d'au moins six notes.
Puis affichez :
- La liste entière, et combien de notes elle contient
- La première et la dernière note — utilisez
[-1]pour la dernière - Le total et la moyenne, accumulés avec une boucle plutôt que tapés à la main
- Une liste numérotée avec
enumerate, à partir de 1 - Une nouvelle liste des notes qui passent (40 ou plus), et combien il y en a
Puis faites deux expériences, et toutes deux comptent :
- Ajoutez une autre note à la fin avec
append, et affichez le total à nouveau. Avez-vous dû changer la ligne qui le calcule ? Si non, vous avez écrit un vrai calcul. - Écrivez
backup = marks, puismarks.append(100), et affichez les deux. Qu'y a-t-il dansbackup? Maintenant faites la même chose avec.copy()et observez la différence.
Cette dernière expérience, ce sont les trois minutes les plus précieuses de ce chapitre. La voir une fois de vos propres yeux signifie ne jamais y passer un après-midi plus tard.
Étape 6 sur 6
Défi — le quiz du chapitre
Dix questions, de la plus facile à la plus difficile. Les dernières sont difficiles exprès.
Connectez-vous pour faire le quiz