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.
Commentaires