Optimisation des chaînes de caractères en Python

Tags associés : , , posté le 21 january 2006


Logo associé au billet intitulé Optimisation des chaînes de caractères en Python

Dans quelles situations utiliser les chaînes de caractère ? Pourquoi pas des listes ? Et les list-comprehension dans tout ça ? Réponses en tests, c'est plein de strings mais ne vous inquiétez pas, rien de sexuel ;)

Considérons une chaîne de caractères assez conséquente :

strings = ["tagada"]*1000000 + ["tsouintsouin"]*1000000

Puis une fonction concaténant tous les tagada :

def foo1():
    string_final = ""
    for string in strings:
        if not "tsouin" in string:
            string_final += string
    return string_final

Nous obtenons une fonction qui met 4,44 secondes pour renvoyer une longue chaîne. Pas vraiment rapide, je suis sûr qu'on pourrait aller plus vite avec des listes :

def foo2():
    string_final = []
    for string in strings:
        if not "tsouin" in string:
            string_final.append(string)
    return "".join(string_final)

Cette fois ce sont 4,65 secondes qui sont nécessaires pour effectuer la même opération... l'ajout d'un élément à une liste est donc très coûteux en temps aussi ! Et c'est loin des « centaines de fois » plus rapide qui peuvent être annoncées. C'est d'ailleurs la raison pour laquelle il existe les comprehension-lists :

def foo3():
    return "".join([string for string in strings if not "tsouin" in string])

Qui ne mettent dans ce cas là que 3,25 secondes ! Voila qui fait réfléchir lors de votre prochaine implémentation ;-). Mais au fait s'il est aussi coûteux en temps d'ajouter des éléments à une liste, pourquoi ne pas créer une chaîne de caractères que l'on découpe ensuite en une liste ?! Farfelu ? Vérifions :

def foo4():
    string_final = ""
    for string in strings:
        if not "tsouin" in string:
            string_final += string + "separateur"
    return string_final.split("separateur")

def foo5():
    string_final = []
    for string in strings:
        if not "tsouin" in string:
            string_final.append(string)
    return string_final

La première fonction renvoie une liste en 17,8 secondes, la seconde en 4,31 secondes, en effet c'était farfelu. Et avec une list-comprehension ? Théoriquement encore plus rapide que précédemment puisque qu'il y a un join() en moins, je vous laisse vérifier.

Conclusion : utilisez les list-comprehension au maximum lorsque c'est possible quitte à faire des [foo(string) for string in strings] s'il y a de gros post-traitements de string. Quant à l'utilisation de concaténation de chaînes de caractères contre l'ajout à une liste, le temps où les listes étaient beaucoup plus rapides est apparemment révolu, choisissez donc en fonction du type de données et non de la rapidité...

[Edit/Erratum] : un billet suivant explique une nouvelle méthode d'utilisation des listes plus rapide que les chaînes de caractères.

Je vous rappelle qu'un billet récapitule l'ensemble des bonnes pratiques et optimisations en Python.

Ajouter un commentaire


Billets contextuels

Bonnes pratiques et astuces Python

Logo associé au billet intitulé Bonnes pratiques et astuces Python

Ça faisait un moment que je n'avais pas parlé des bonnes pratiques Python mais l'approche de Pycon fr (où je présenterai Django : le pourquoi et le comment le 18 mai), l'événement Python incontournable avec un programme des ...

Benchmarks map, filter vs. list-comprehensions

Logo associé au billet intitulé Benchmarks map, filter vs. list-comprehensions

Je viens de tomber sur les snyppets de Seb Sauvage (site que j'apprécie beaucoup par ailleurs) et il y a une phrase qui m'a interpellé sur le paragraphe consacré à zip, map, filter et aux list-comprehensions : Except that ...

Python : lisibilité vs simplicité

Logo associé au billet intitulé Python : lisibilité vs simplicité

Le programmeur est fainéant. C'est ainsi. S'il ne l'était pas, il n'essayerait pas de s'aider d'un ordinateur. Du coup il évite dans la mesure du possible de s'encombrer de variables trop longues, ou ...


© 2004-2008 David Larlet - Licence (presque) libre - Site enfin propulsé par Django et hébergé par Typhon.