Le slicing en Python : découper une liste ou une chaîne

Le slicing découpe une portion d'une séquence Python avec des crochets et un deux-points, et renvoie une nouvelle liste ou une nouvelle chaîne.
6 min de lecture
Believemy logo

Définition

Il arrive souvent qu'on ait besoin d'une seule partie d'une liste ou d'une chaîne : les trois premiers résultats d'une recherche, tout sauf le dernier élément, un nom sur deux dans un fichier. Écrire une boucle pour les extraire un par un fonctionne, mais alourdit le code. Le slicing répond directement à ce besoin.

Il découpe une portion d'une séquence et renvoie un nouvel objet, sans toucher à l'original. L'écriture tient en deux nombres séparés par un deux-points, entre crochets : sequence[debut:fin]. Voici ce que ça donne sur une liste de mois :

PYTHON
mois = ["janvier", "février", "mars", "avril", "mai"]

premier_trimestre = mois[0:3]
# ['janvier', 'février', 'mars']

Cette écriture s'applique à tout ce qui se parcourt par rang : une liste, un tuple, une chaîne de caractères, un objet range. Un dictionnaire, lui, n'en accepte aucun : il n'a pas de rang, seulement des clés.


La borne de fin reste dehors

Le premier rang est inclus, le second exclu. Cette asymétrie déroute au début, mais elle rend service assez vite : la taille de la tranche vaut exactement fin - debut, et deux tranches qui se rejoignent au même rang reconstituent la séquence entière, sans doublon ni trou. Voici ce principe sur le mot Python, découpé entre les rangs 1 et 4 :

Les bornes d'un découpage se posent entre les élémentsLes six caractères du mot Python portent leurs rangs positifs de 0 à 5 au-dessus et leurs rangs négatifs de -6 à -1 en dessous. Les bornes 1 et 4 du découpage se posent dans les intervalles entre les caractères, jamais sur eux : la tranche retient les rangs 1, 2 et 3, et laisse le rang 4 dehors."Python"[1:4]début 1fin 4rangs positifsPython012345-6-5-4-3-2-1rangs négatifsrésultat : "yth"la borne 4 se pose avant le rang 4, qui reste dehors

Le calcul suivant le vérifie :

PYTHON
mois[:2] + mois[2:] == mois
# True

Les deux bornes sont d'ailleurs facultatives. Omettre la première part du début, omettre la seconde va jusqu'à la fin, omettre les deux renvoie la séquence complète. Un rang négatif compte depuis la fin, ce qui dispense de calculer une longueur avec len pour atteindre les derniers éléments. Voici les écritures les plus utiles :

ÉcritureCe qu'elle renvoie
mois[2:]Du troisième élément jusqu'à la fin
mois[:2]Les deux premiers éléments
mois[-2:]Les deux derniers éléments
mois[:-1]Tout sauf le dernier
mois[::2]Un élément sur deux
mois[::-1]La séquence dans l'ordre inverse
Découpez la liste et voyez ce qui sort
lettres[1:6:1]
a
0
-8
b
1
-7
c
2
-6
d
3
-5
e
4
-4
f
5
-3
g
6
-2
h
7
-1
1
6
1
Résultat
['b', 'c', 'd', 'e', 'f']

Le pas est positif, la lecture va de gauche à droite et s'arrête avant la borne de fin, qui est exclue.

Les rangs négatifs comptent depuis la fin. Le découpage ne lève jamais d'erreur, même hors limites : c'est ce qui le distingue de l'accès direct par rang.


Le pas, ce troisième nombre

Un deuxième deux-points introduit le pas : sequence[debut:fin:pas]. Il vaut 1 par défaut et indique de combien de rangs avancer entre deux éléments retenus. Voici ce que ça change sur une liste de dix nombres :

PYTHON
nombres = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

nombres[::3]     # [0, 3, 6, 9]
nombres[1:8:2]   # [1, 3, 5, 7]

Un pas négatif parcourt la séquence à l'envers. C'est de là que vient l'écriture la plus reconnaissable du langage, sequence[::-1], qui renvoie la séquence retournée, sur une chaîne comme sur une liste.

Attention

Avec un pas négatif, les bornes se lisent aussi à l'envers : debut doit dépasser fin, pas l'inverse. nombres[2:8:-1] ne renvoie donc pas les rangs 2 à 8 retournés, mais une liste vide, puisqu'on ne peut pas reculer du rang 2 vers le rang 8.


Il ne lève jamais d'erreur de rang

Demander un rang qui n'existe pas à une séquence interrompt normalement le programme : sur une liste de cinq mois, mois[10] lève une IndexError. Une tranche se comporte pourtant autrement.

PYTHON
resultats = []
premiers = resultats[:3]

# [] et non une erreur

mois[10:20] sur cinq éléments renvoie tranquillement une liste vide. Le découpage rabote les bornes sur la taille réelle de la séquence au lieu de protester quand elles vont trop loin.

Cette tolérance est une bénédiction pour lire les trois premiers résultats d'une recherche ou les premières lignes d'un fichier. Elle devient un piège quand elle masque un jeu de données vide : une tranche vide ne signale rien. Si la suite du programme suppose au moins un élément, mieux vaut le vérifier explicitement plutôt que compter sur le découpage pour prévenir.


Une copie de surface, et l'affectation par tranche

Sur une liste, le découpage renvoie toujours un nouvel objet : copie = original[:] est l'écriture courte d'une copie complète, sans écrire de boucle.

Attention

Cette copie reste superficielle : les éléments ne sont pas dupliqués. Si la liste contient d'autres listes, les deux versions partagent leur contenu, et modifier un élément mutable d'un côté se voit de l'autre.

Sur une chaîne, la question ne se pose pas : le texte est immuable, et le découper produit toujours une valeur indépendante.

À gauche du signe égal, la tranche change de rôle : elle ne lit plus, elle remplace. La liste est modifiée sur place, et le nombre d'éléments insérés n'a pas besoin de correspondre à celui de la tranche retirée :

PYTHON
mois[1:3] = ["printemps"]

# la liste raccourcit d'un élément

La même logique vaut pour del : del mois[1:3] retire la tranche et referme la liste derrière elle. Ces deux écritures ne valent en revanche que sur les séquences modifiables. La même tentative sur un tuple ou sur une chaîne lève une TypeError.


Questions fréquentes

Question

Pourquoi ma tranche contient-elle un élément de moins que prévu ?

Parce que la borne de fin est exclue. Pour obtenir les rangs 2 à 5 inclus, il faut écrire [2:6] et non [2:5]. Le réflexe qui évite définitivement l'erreur consiste à lire le second nombre comme « on s'arrête avant celui-ci », jamais comme « jusqu'à celui-ci ».

Question

Peut-on utiliser des nombres à virgule dans une tranche ?

Non, les bornes et le pas doivent être des entiers de type int. Un nombre à virgule lève une TypeError même lorsqu'il tombe rond, ce qui surprend après une division : celle-ci renvoie toujours un flottant, et il faut passer par la division entière avec // pour obtenir un rang valable.

Question

Comment découper un dictionnaire ?

Il n'existe pas de découpage sur un dictionnaire, puisque ses clés n'ont pas de rang à désigner. Pour n'en garder qu'une partie, on filtre les clés retenues dans une compréhension de liste appliquée aux couples, ce qui reconstruit un dictionnaire réduit.

Termes connexes

Découvrez notre glossaire Python

Parcourez les termes et définitions les plus couramment utilisés dans le domaine du développement avec Python.

Partager cet article

Tu veux nous aider ? Fais un lien vers cet article sur tes réseaux ou encore mieux : sur ton site, dans un article ou dans ta newsletter.