Notes apprentissage : une séquence renversante
Contenu
Contexte
Python est un langage de programmation très abordable que l’on démarre en programmation ou que l’on connaisse déjà d’autres langages. Néanmoins, ce n’est pas parce qu’un langage est abordable qu’il n’a pas ses propres idiomes et qu’il n’y a pas des trucs & astuces à connaître et à retenir.
Ci-après, une petite note d’apprentissage de Python, sur la manière d’inverser les éléments d’une liste et d’une chaine de caractères.
NB : c’est du Python 3 qui est utilisé.
Liste
Pour inverser les éléments d’une liste, il y a d’abord la méthode reverse()
des listes. Cette méthode s’appelle directement sur la liste et inverse les éléments de la liste en modifiant la liste. Cela sera plus clair avec un exemple :
|
|
Si on exécute ces lignes, cela nous donne :
|
|
La liste est donc irrémédiablement modifiée. Cela peut correspondre à votre besoin, mais dans tous les cas, il vaut mieux le savoir. Maintenant, que se passe-t-il si je veux inverser l’ordre des éléments de la liste sans modifier la liste. Nous avons 2 options : utiliser la fonction reversed()
et mettre à profit les slices.
Renversement de situation
On peut utiliser la fonction reversed()
qui prend en paramètre une liste et retourne une liste dont les éléments sont dans l’ordre inverse. Cette fois-ci la liste originale n’est plus modifiée :
|
|
ce qui donne :
|
|
Comme on peut le constater dans l’exemple, reversed()
ne modifie pas la liste elle-même. Elle retourne un iterable
dont la séquence d’éléments est dans l’ordre inverse de la séquence de départ. C’est un iterable
qui est retourné, c’est pour cela que pour pouvoir le faire s’afficher sous forme de liste dans le dernier print
, on le convertit d’abord en liste avec list(reversed_numbers)
.
Bien sûr, si vous voulez itérer sur une séquence dans l’ordre inverse, vous allez utiliser reversed()
, et oui bien sûr cela fonctionne sur d’autres itérables que les listes (dans l’exemple ci-après avec un range
), si l’inversion a du sens :
|
|
ce qui donne :
|
|
Si vous connaissez un peu Python, vous ne manquerez pas de voir une similitude entre d’une part la méthode reverse()
et la fonction reversed()
et d’autre part la méthode sort()
et la fonction sorted()
.
A noter que cela fonctionne également pour les tuples :
|
|
La tranche à l’envers
Les slices sont un outil pervasif en Python dès que l’on a besoin de manipuler des listes ou des chaines de caractères. Sans rentrer dans le détails du fonctionnement des slices auxquelles il faudrait consacrer un billet spécifique, je vais juste les présenter rapidement afin que l’on voit comment on peut les mettre à profit pour inverser notre liste.
Il faut se rappeler qu’en Python, classiquement les éléments d’une listes sont indexés de 0 (indice du premier élément) à la taille de la liste moins un (indice du dernier élément). La liste ['a', 'b', 'c', 'd', 'e', 'f']
à 6 éléments indexés de 0 à 5. Moins classiquement, on peut utiliser des indices négatifs : le dernier élément à l’indice -1 et le premier élément à l’indice -(taille de la liste). Sur la liste précédente les indices négatifs vont ainsi de -6 à -1.
En Python, on peut indiquer un indice (pour le compte positif ou négatif) pour récupérer l’élément de la liste. Par exemple, dans l’interptéteur on pourra avoir :
|
|
Mais il est également possible de préciser une tranche, un segment de la liste que l’on souhaite récupérer (en anglais, une slice), en précisant entre les crochets, un indice de départ, un indice de fin (élément associé à cet indice non-inclus dans la slice créé), et un pas d’avancement, chaque valeur séparée de la précédente par deux points (:
). Par exemple, en poursuivant sur l’exemple précédent dans l’interpréteur :
|
|
Sur le même principe que précédemment, on peut préciser des indices négatifs et un pas d’avancement négatifs. Un pas d’avancement négatifs de changer le sens de parcours. Par exemple, toujours en poursuivant l’exemple précédent dans l’interpréteur.
|
|
On peut mélanger des indices négatifs et positifs avec un pas d’avancement positif ou négatifs, il faut juste que l’indice de début et celui de fin soit cohérent par rapport au pas d’avancement donné : pour un pas d’avancement positif, il faut que l’indice de début soit plus petit que l’indice de fin et pour un pas d’avancement négatif, que l’indice de début soit plus grand que l’indice de fin, sinon on obtient une liste vide. En continuant avec l’interpréteur :
|
|
Avec la syntaxe des slices, on peut ne pas préciser la valeur de l’indice de départ, la valeur de l’indice de fin ou celui du pas d’avancement. Dans ce cas des valeurs par défaut sont utilisés. Ainsi si on ne précise aucune valeur, on va obtenir une copie de la liste :
|
|
Par défaut la valeur de l’indice de la liste est 0, celui de l’indice de fin est la taille de la liste et le pas d’avancement est 1. Regardez maintenant ce qui se passe si je précise une valeur de pas d’avancement de -1 :
|
|
Dans ce cas, j’obtiens une copie de la liste avec les éléments dans l’ordre inverse. Vous l’avez compris, c’est notre troisième manière d’inverser l’ordre des éléments de la liste.
On notera au passage, que les valeurs par défaut pour l’indice de départ et de fin ne sont plus respectivement 0 et la taille de la liste, mais que les valeurs sont inversées. J’avoue je n’ai pas creusé pour avoir tous les détails, je suis resté au niveau de l’expérimentation.
|
|
A noter que cela fonctionne également pour les tuples :
|
|
Chaines de caractères
Pour les chaines de caractères, il est possible d’utiliser reversed
et la slice avec un indice négatif.
Partir à la renverse
Si on utilise reversed
, on n’obtient pas directement une chaine de caractères :
|
|
Ce qui donne :
|
|
On peut quand même l’afficher moyennant un peu de travail :
|
|
Avec pour résultat :
|
|
Néanmoins, comme pour les listes, l’intérêt d’utiliser reversed
c’est pour l’utiliser dans une boucle ou dans une compréhension.
|
|
Ce qui donne :
|
|
Trancher dans le vif
L’utilisation de la syntaxe d’une slice pour inverser une chaine fonctionne de la même manière que pour une liste. Cela crée une nouvelle chaine et c’est utilisable dans une boucle for ou une compréhension.
|
|
Ce qui donne :
|
|
Synthèse
Solution | Impacts |
---|---|
méthode reverse() |
valable uniquement sur les listes, modifie la liste |
fonction reversed() |
valable sur les listes, les tuples et les chaines ; retourne une nouvelle séquence avec les éléments dans l’ordre inverse |
notation [::-1] |
valable sur les listes, les tuples et les chaines ; retourne une nouvelle séquence avec les éléments dans l’ordre inverse |
Ma première impression est que la manière idiomatique de le faire en Python est d’utiliser la notation [::-1] pour inverser une chaine de caractères. De toutes façons, il faut savoir utiliser les slices en Python, on se prive quand même d’un outil bien pratique sinon.
Je trouve que dans une boucle ou une comprehension reversed
véhicule clairement l’intention même si quand on est habitué à lire [::-1]
on la comprend tout aussi bien. Dans tous les cas, j’aurais tendance à n’utiliser reversed
que dans une boucle, pour juste récupérer une chaine ou une liste inversée la notation [::-1]
semble directe. Je n’ai pas fait de tests mais j’imagine que reversed
est probablement préférable pour inverser les très longues listes ou chaînes sur lesquelles on souhaiterait itérer.
Il faut connaître à mon sens la méthode reverse()
, savoir qu’elle existe et ce qu’elle fait, mais contre il faut vraiment avoir un besoin spécifique : je préfère éviter une méthode qui modifie directement l’objet sous-jacent, à part si j’ai vraiment une bonne raison de le faire.
Le gist avec les exemples de code.
Auteur TGITS
Modifié 2020-11-15