Inverser une chaine de caractères en Python

Inverser des collections est une opération standard en informatique. Mais le débutant en Python est un peu perdu pour les chaines de caractères. Contrairement aux listes, il n’existe pas de méthode qui permet cette inversion, c’est à dire obtenir « cba » à partir de « abc ».

Alors le développeur fait ce que que fait tout développeur : il cherche sur le net…

J’ai fait cette recherche sur Google et je vais admettre que les résultats qui sortent (sortaient car grâce à vous cet article est dans le top) en tête sont… terrifiants. En fait, ils illustrent une méconnaissance de Python et de ses idiomes.

Alors allons-y pour la manière la plus propre en Python.

Rappel sur les chaines de caractères et idiomes en Python

Il est indispensable de rappeler qu’en Python, les chaines sont immuables. Il est impossible de les modifier, c’est à dire de remplacer un caractère, en ajouter ou en supprimer. Il n’y a donc pas de méthode reverse() comme pour les listes. En effet, pour les listes, reverse() ne retourne rien car elle modifie la liste originale, la donnée originale.

In [1]camelot = ["Arthur", "Lancelot", "Robin"]                               

In [2]: camelot.reverse()                                                       

In [3]: camelot                                                                 
Out[3]: ['Robin', 'Lancelot', 'Arthur']

Si la même méthode était proposée pour des chaines de caractères, elle devrait avoir le même comportement : ne rien retourner et modifier la donnée originale. Ce qui est donc impossible…

La fonction reversed()

Petit rappel, il existe en Python une fonction built-in qui s’appelle reversed(seq). Celle-ci prend en paramètre une séquence (donc peut prendre une chaine de caractères) et retourne un itérateur sur l’inverse de la séquence.

In [1]: reversed("abc")                                                        
Out[1]: <reversed at 0x104ff97d0>

Nous pouvons donc l’utiliser avec la méthode join() pour créer la chaine de sortie.

In [2]: "".join(reversed("abc"))                                               
Out[2]: 'cba'

Et voilà une première manière d’obtenir le résultat.

Et le slicing ?

Si vous ne connaissez pas le slicing qui s’applique à toutes les séquences, je vous invite à consulter la documentation ou au moins mon article dédié. Le slicing est un outil très puissant en Python pour lequel il est indispensable de se rappeler qu’il peut accepter trois paramètres. Ce dernier permet de spécifier un pas qui peut être négatif. Ainsi, vous pouvez simplifier l’inversion d’une chaine de caractères de la manière suivante :

In [1]: "abc"[::-1]                                                            
Out[1]: 'cba'

Sémantiquement, on ne peut pas faire plus simple. De plus, c’est la manière la plus Pythonique.

La chose à ne pas faire !

La chose à ne pas faire, c’est d’écrire le code suivant :

In [1]: def miror(seq): 
   ...:     rseq = "" 
   ...:     for char in seq: 
   ...:         rseq = char + rseq 
   ...:     return rseq 
   ...:                                                                        

In [2]: miror("abc")                                                           
Out[2]: 'cba'

Ce type de code traine en tête des résultats Google pour la requête « inverser chaine Pyhton ». Et il est mauvais pour plusieurs raisons.

La première est une question de ressources. N’oubliez pas qu’en Python, les variables sont des références vers les données. À chaque itération, une nouvelle chaine de caractères est créée par concaténation du caractère et de la séquence précédente. De plus, la variable rseq change de référence à chaque itération.

La seconde grosse raison est une question de lisibilité. Il faut 4 lignes pour comprendre l’intention de ce code. La lisibilité compte, pensez à celui qui lira le code.

La troisième mérite sa propre partie.

Et la question de la performance

Voyons donc la question de la performance pour ces trois types d’instructions :

In [1]: %timeit "".join(reversed("abs"))                                       
397 ns ± 5.7 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

In [2]: %timeit "abc"[::-1]                                                    
112 ns ± 0.763 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)

In [3]: %timeit miror("abc")                                                   
390 ns ± 66.3 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

Et oui, utiliser la méthode avec la fonction reversed(seq) est presque 4 fois plus lent que le slicing… Et du même ordre de grandeur que l’itération.

De manière indéniable, c’est le slicing qui se démarque.

Le code ne doit plus avoir de secret pour vous ! (source inconnue)

La prochaine fois que vous devrez inverser une chaine en Python, dites vous que vous n’avez même pas besoin de fonction.

Si vous avez aimé ce post, n’hésitez pas à laisser un commentaire ci-dessous ou sur la page Facebook 😉

À propos de... Darko Stankovski

iT guy, photographe et papa 3.0, je vous fais partager mon expérience et découvertes dans ces domaines. Vous pouvez me suivre sur les liens ci-dessous.

Vous aimerez aussi...

3 réponses

  1. Merci pour le rappel et la notion de performance

  2. Loulou Azar dit :

    cool

  1. 1 décembre 2019

    […] y a quelques jours, dans l’article vous montrant comment inverser une chaine de caractères en Python, j’ai utilisé le slicing. C’est un outil indispensable en Python qui permet de […]

Répondre à Loulou AzarAnnuler la réponse.

En naviguant sur Dad 3.0, vous acceptez l’utilisation de cookies pour une navigation optimale et nous permettre de réaliser des statistiques de visites. Plus d'informations

Le blog Dad 3.0 utilise les cookies pour vous permettre une navigation optimale et nous permettre de réaliser des statistiques de visite. Dad 3.0 affichant des publicités, celles-si utilisent également des cookies pour un ciblage publicitaire. En continuant la navigation sur Dad 3.0, vous acceptez le dépôt et la lecture de cookies.

Fermer