title: Benchmarks map, filter vs. list-comprehensions slug: benchmarks-map-filter-vs-list-comprehensions date: 2006-10-25 19:00:06 type: post vignette: images/logos/seb_sauvage.png contextual_title1: Bonnes pratiques et astuces Python contextual_url1: 20080511-bonnes-pratiques-et-astuces-python contextual_title2: Python : lisibilité vs simplicité contextual_url2: 20060425-python-et-underscore contextual_title3: Principales nouveautés dans Python 2.5 contextual_url3: 20060304-principales-nouveautes-dans-python-25
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 {map|filter} is faster. (than list-comprehensions)
Ni une, ni deux, je récupère l'article de Tarek qui est très bon et qui comporte une fonction testant la durée d'execution des fonctions pour pouvoir comparer. J'avais déjà essayé d'autres fonctions mais autant innover un peu.
Allons-y donc avec le décorateur suivant :
from test import pystone import time kPs = 1000 TOLERANCE = 0.5 * kPs def mesure_pystone(): pystone.pystones(loops=pystone.LOOPS) pystone.pystones(loops=pystone.LOOPS) return pystone.pystones(loops=pystone.LOOPS) def timedtest(function, local_pystones=mesure_pystone()): """ Decorator to measure execution time in pystones """ def wrapper(*args, **kw): all = [] for i in range(3): start_time = time.time() try: res = function(*args, **kw) finally: total_time = time.time() - start_time if total_time == 0: temps = 0 else: ratio = local_pystones[0] / local_pystones[1] temps = total_time / ratio all.append(temps) print '%d pystones' % min(all) return res return wrapper
J'ai testé les fonctions suivantes qui ne sont pas les mêmes que les exemples de Seb mais qui retournent (elles, merci Haypo :-)) le même résultat :
@timedtest def map_without_list_comprehension(): for i in range(10000): map(abs, [-5,7,-12]) @timedtest def map_with_list_comprehension(): for i in range(10000): [abs(i) for i in [-5,7,-12]] print '=== map vs. list-comprehension ===' print 'map without list-comprehension:' map_without_list_comprehension() print 'map with list-comprehension:' map_with_list_comprehension() @timedtest def filter_without_list_comprehension(): for i in range(10000): filter(abs, [-5,7,0,-12] ) @timedtest def filter_with_list_comprehension(): for i in range(10000): [i for i in [-5,7,0,-12] if i] print '=== filter vs. list-comprehension ===' print 'filter without list-comprehension:' filter_without_list_comprehension() print 'filter with list-comprehension:' filter_with_list_comprehension()
Et voila les résultats obtenus :
=== map vs. list-comprehension ===
map without list-comprehension:
638 pystones
map with list-comprehension:
534 pystones
=== filter vs. list-comprehension ===
filter without list-comprehension:
612 pystones
filter with list-comprehension:
550 pystones
Il me semble que c'est sans appel : les list-comprehensions sont toujours plus rapides que map ou filter avec Python 2.4. Il faudrait tester tout ça avec Python 2.5 mais je pense que les résultats seraient encore plus significatifs.