Quantcast
Channel: AFPy's Planet
Viewing all articles
Browse latest Browse all 3409

Petit benchmark...

$
0
0

Coucou,

Au hasard de mes pérégrinations, j’ai souhaité vérifié qu’un fichier correspond à une extension précise, parmi une liste d’extensions bien entendu.

Je fais donc une recherche, pour chaque fichier, parmi toutes les extensions listées pour voir s’il en fait partie ou pas.

J’ai donc commencé par un truc tout bête, genre :

if name[:-3] in (liste des extensions):

Et forcément, ça ne fonctionne que pour des extensions de 3 caractères. Oubliées les “.md” et autres “.epub”

J’ai donc amélioré la chose avec une simple liste de compréhension :

[1 for extension in test_extensions if name.endswith(extension)]

Ici, name est le nom du fichier, test_extensions est la liste d’extensions à tester. Je crée donc une liste qui contiendra un élément si mon fichier correspond à une extension, sinon la liste sera vide. Il me suffit alors de vérifier la longueur de la liste résultante.

Et puis j’ai pensé à utiliser filter qui est souvent bien pratique :

list(filter(lambda x: name.endswith(x), test_extensions))

C’est plus court, mais pas forcément plus lisible je trouve. Pour faire plus court, on peut remplacer list par set (oui, on y gagne 1 seul caractère, c’est de l’optimisation de forcené qui n’a rien d’autre à faire de ses journées :smiley: )

J’ai aussi voulu tester avec map :

list(filter(None, map(name.endswith, test_extensions)))

Et c’est encore plus court finalement ! Ah ah ah ! Mais peut-être encore moins lisible ?

Bon, et forcément, vu que mon projet n’est pas si important, j’ai largement le temps de faire un poil de benchmark :

import pathlib
import random
import timeit

# On prépare les données
extensions = ("txt", "png", "md", "ico", "gif", "zip", "rst", "epub",)
test_extensions = (".txt", ".rst", ".md")
files = []
for i in range(10):
    files.append(f"test.{random.choice(extensions)}")

# On lance les banchmarks
print("set, filter map")
print(timeit.timeit("[len(set(filter(None, map(name.endswith, test_extensions)))) for name in files]", globals=globals(), number=100000))
print("list, filter map")
print(timeit.timeit("[len(list(filter(None, map(name.endswith, test_extensions)))) for name in files]", globals=globals(), number=100000))
print("set, filter lambda")
print(timeit.timeit("[len(set(filter(lambda x: name.endswith(x), test_extensions))) for name in files]", globals=globals(), number=100000))
print("list, filter lambda")
print(timeit.timeit("[len(list(filter(lambda x: name.endswith(x), test_extensions))) for name in files]", globals=globals(), number=100000))
print("simple")
print(timeit.timeit("[len([1 for extension in test_extensions if name.endswith(extension)]) for name in files]", globals=globals(), number=100000))
print("pathlib")
print(timeit.timeit("[pathlib.PurePosixPath(name) in test_extensions for name in files]", globals=globals(), number=100000))

Et voici les résultats (obtenus sur mon PC, sous Windows 10 (je suis au bureau, désolé)) :

set, filter map
0.8425506
list, filter map
0.870825
set, filter lambda
1.0246678000000002
list, filter lambda
1.0588134
simple
0.7103302
pathlib
3.2523364

Émerveillement de la nature, on s’aperçoit que list est légèrement plus lente que set, mais surtout qu’on s’en sort très bien sans filter.
Pour information, l’ajout du calcul de la longueur ne joue pas sur les temps de réponse.

La morale de cette histoire ?

  1. Les fonctions intégrées sont souvent intéressantes, mais elles ne font pas tout
  2. J’ai vraiment du temps à perdre ce matin

Voilà, et bonne journée à vous !

EDIT : Ajout de pathlib, qui est donc à oublier même si très pratique :wink:

10 messages - 4 participant(e)s

Lire le sujet en entier


Viewing all articles
Browse latest Browse all 3409

Trending Articles