Optimisation des chaînes de caractères en Python : le retour !

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


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

Dans les épisodes précédents, je m'étonnais de voir des concaténations de chaînes de caractères être plus rapide que des remplissages de listes. Depuis je cogite car il est indiqué un peu partout qu'il faut privillégier les listes. Et j'ai fini par trouver une réponse :-).

Considérons la même chaîne de caractères :

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

Et la même fonction foo2() :

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

Donc cette fonction met environ 4,70 secondes à créer cette énorme chaîne de caractères. Ce que j'avais alors oublié de tester, ce sont les alias. En effet, les fonctions de type list.append sont réévaluées à chaque itération en python, ce qui fait perdre un temps fou, la preuve en chiffres :

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

Et là on tombe à 3,50 secondes ! Ainsi les listes peuvent être plus rapides que les concaténations de chaînes de caractères, encore faut-il pouvoir créer un alias...

Bon et puisque j'y suis, une autre petite astuce d'optimisation : on peut lire dans les astuces d'optimisation de Zope qu'il vaut mieux utiliser les méthodes du module string plutôt que des portions de listes. Bon dit comme ça on comprend pas trop de quoi je parle alors un petit exemple pour clarifier tout ça :

def foo4():
    string_final = ""
    for string in strings:
        if string[:5] == "tagad":
            string_final += string
    return string_final

def foo5():
    string_final = ""
    for string in strings:
        if string.startswith("tagad"):
            string_final += string
    return string_final

La méthode foo4() s'exécute en 7,2 secondes et foo5() en 12 secondes... tiens c'est le contraire qui est obtenu ici, me serais-je trompé ? Je revérifie et non j'ai bien ces temps là d'exécution, soit presque le double lorsque l'on utilise les méthodes du module string.

Première conclusion : vérifiez toujours les astuces d'optimisation qu'on vous propose (ceci est valable pour celles-ci aussi) car elle peuvent évoluer selon les versions de Python ou du contexte par exemple.

Seconde conclusion : les listes finalement c'est pas si mal pour traiter les chaînes de caractères :-).

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

4 Commentaires

C'est le genre de truc qui me fait peur quand je me dis que je vais apprendre python (c'est aussi valable pour les autres ). On peut faire une opération de bien ?!trop?! de manières différentes, avec des implications conséquentes. Il me faut trouver le livre idéal qui m'apprenne et me sensibilise à ce genre de problème.

1 | Kagou, le 27 January 2006 à 13h

Non justement en Python il y a très souvent une seule manière de bien faire les choses et c'est d'ailleurs la raison d'être de ces billets :)

2 | David, biologeek, le 27 January 2006 à 14h

En fait entre Python 2.3 et Python 2.4 la gestion des chaînes a changée, rendant obsolètes et parfois même plus lentes des astuces qu'on trouve encore sur le web.

Conclusion: il faut toujours indiquer la version de Python utilisée dans les astuces de ce genre.

3 | Tarek, le 11 March 2006 à 21h

Oui, je l'ai appris en lisant un très bon livre, je suis d'ailleurs en train d'en écrire une critique ;)

4 | David, biologeek, le 11 March 2006 à 21h

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-2010 David Larlet - Licence (presque) libre - Site enfin propulsé par Django et hébergé par Typhon.