09 - Slicing

Introduction

Le slicing (ou « tranchage ») est une technique fondamentale de Python qui permet d’extraire une sous-séquence à partir d’une séquence (liste, chaîne de caractères, tuple). C’est l’un des outils les plus puissants et les plus élégants du langage.

Imaginez une baguette de pain : le slicing revient à en couper une tranche entre deux positions. Vous choisissez où commencer, où finir, et éventuellement vous ne prenez qu’une rondelle sur deux.

Rappel : indexation

Avant de découper, rappelons comment Python numérote les éléments d’une séquence. Considérons la liste :

L = ['a', 'b', 'c', 'd', 'e', 'f']

Les indices positifs commencent à 0 et les indices négatifs comptent à partir de la fin :

Éléments :   a    b    c    d    e    f
Indices + :  0    1    2    3    4    5
Indices - : -6   -5   -4   -3   -2   -1

Ainsi L[0] vaut 'a', L[3] vaut 'd', L[-1] vaut 'f' et L[-2] vaut 'e'.

Syntaxe du slicing

La syntaxe générale est :

L[début:fin:pas]

où :

  • début est l’indice du premier élément sélectionné (inclus) ;
  • fin est l’indice de fin (exclu, comme pour range()) ;
  • pas est l’écart entre deux indices successifs (par défaut 1).

Le résultat est toujours une nouvelle séquence du même type.

Analogie avec les intervalles mathématiques : le slicing L[i:j] correspond à l’intervalle \([i\,;\, j[\), c’est-à-dire que la borne de fin n’est jamais incluse.

Exemples de base

L = ['a', 'b', 'c', 'd', 'e', 'f']
print(L[1:4])    # ['b', 'c', 'd']  — indices 1, 2, 3
print(L[0:3])    # ['a', 'b', 'c']  — les 3 premiers
print(L[2:5])    # ['c', 'd', 'e']  — indices 2, 3, 4

Visualisons le premier exemple :

Éléments :  a    b    c    d    e    f
Indices :   0    1    2    3    4    5
                 ^---------^
              début=1    fin=4 (exclu)
Résultat : ['b', 'c', 'd']

Valeurs par défaut

On peut omettre un, deux ou les trois paramètres :

L = ['a', 'b', 'c', 'd', 'e', 'f']

print(L[:3])     # ['a', 'b', 'c']  — début omis → commence à 0
print(L[3:])     # ['d', 'e', 'f']  — fin omise → va jusqu'à la fin
print(L[:])      # ['a', 'b', 'c', 'd', 'e', 'f']  — copie complète
print(L[::2])    # ['a', 'c', 'e']  — un élément sur deux

Règle générale :

  • si début est omis, il vaut 0 (début de la séquence) ;
  • si fin est omise, elle vaut len(L) (fin de la séquence) ;
  • si pas est omis, il vaut 1.

Slicing avec des indices négatifs

Les indices négatifs fonctionnent aussi dans le slicing :

L = ['a', 'b', 'c', 'd', 'e', 'f']

print(L[:-1])    # ['a', 'b', 'c', 'd', 'e']  — tout sauf le dernier
print(L[-3:])    # ['d', 'e', 'f']  — les 3 derniers
print(L[-4:-1])  # ['c', 'd', 'e']  — du 4e avant la fin au dernier (exclu)
print(L[1:-1])   # ['b', 'c', 'd', 'e']  — sans le premier ni le dernier

Slicing avec un pas

Le troisième paramètre permet de sauter des éléments :

L = ['a', 'b', 'c', 'd', 'e', 'f']

print(L[::2])    # ['a', 'c', 'e']  — un sur deux, en partant du début
print(L[1::2])   # ['b', 'd', 'f']  — un sur deux, en partant de l'indice 1
print(L[::3])    # ['a', 'd']       — un sur trois

Pas négatif : parcours en sens inverse

Avec un pas négatif, Python parcourt la séquence de droite à gauche :

L = ['a', 'b', 'c', 'd', 'e', 'f']

print(L[::-1])   # ['f', 'e', 'd', 'c', 'b', 'a']  — liste inversée
print(L[::-2])   # ['f', 'd', 'b']  — un sur deux, en sens inverse
print(L[4:1:-1]) # ['e', 'd', 'c']  — de l'indice 4 à l'indice 2 (1 exclu)

Valeurs par défaut avec un pas négatif :

  • si début est omis, il vaut -1 (dernier élément) ;
  • si fin est omise, elle vaut au-delà du premier élément (c’est-à-dire que tout est pris).

Attention : slicing vs indexation

L[1] et L[1:2] ne renvoient pas la même chose :

L = ['a', 'b', 'c', 'd', 'e', 'f']

a = L[1]      # 'b'          — un élément (type str)
b = L[1:2]    # ['b']        — une liste à un élément (type list)
print(type(a), a)   # <class 'str'> b
print(type(b), b)   # <class 'list'> ['b']

L’indexation renvoie l’élément lui-même, le slicing renvoie une nouvelle séquence.

Slicing sur les chaînes de caractères

Le slicing fonctionne exactement de la même manière sur les chaînes :

mot = "informatique"

print(mot[:5])     # 'infor'
print(mot[5:])     # 'matique'
print(mot[::2])    # 'ifraiu'
print(mot[::-1])   # 'euqitamrofni'  — chaîne inversée

Modification par slicing (listes uniquement)

Sur une liste (séquence muable), le slicing peut être utilisé pour remplacer une portion :

L = ['a', 'b', 'c', 'd', 'e', 'f']
L[2:4] = ['X', 'Y', 'Z']
print(L)  # ['a', 'b', 'X', 'Y', 'Z', 'e', 'f']

On a remplacé deux éléments ('c' et 'd') par trois éléments. La taille de la liste change.

Attention : cela ne fonctionne pas sur les chaînes de caractères (qui sont immutables).

Résumé

ExpressionSignification
L[i:j]Éléments de l’indice i à j-1
L[:j]Les j premiers éléments
L[i:]Du i-ème à la fin
L[:]Copie complète
L[::k]Un élément sur k
L[::-1]Séquence inversée
L[i:j:k]De i à j-1, par pas de k