¿Es el valor predeterminado en el módulo de colecciones de Python realmente más rápido que usar setdefault?
collections defaultdict (1)
He visto a otros programadores de Python usar defaultdict del módulo de colecciones para el siguiente caso de uso:
from collections import defaultdict
s = [(''yellow'', 1), (''blue'', 2), (''yellow'', 3), (''blue'', 4), (''red'', 1)]
def main():
d = defaultdict(list)
for k, v in s:
d[k].append(v)
Por lo general, he abordado este problema utilizando setdefault en su lugar:
def main():
d = {}
for k, v in s:
d.setdefault(k, []).append(v)
De hecho, los documentos afirman que el uso de defaultdict es más rápido , pero he visto que lo contrario es cierto al probarme a mí mismo:
$ python -mtimeit -s "from withsetdefault import main; s = [(''yellow'', 1), (''blue'', 2), (''yellow'', 3), (''blue'', 4), (''red'', 1)];" "main()"
100000 loops, best of 3: 4.51 usec per loop
$ python -mtimeit -s "from withdefaultdict import main; s = [(''yellow'', 1), (''blue'', 2), (''yellow'', 3), (''blue'', 4), (''red'', 1)];" "main()"
100000 loops, best of 3: 5.38 usec per loop
¿Hay algún problema con la forma en que he configurado las pruebas?
Para referencia, estoy usando Python 2.7.3 [GCC 4.2.1 (Apple Inc. build 5666)
Sí, hay algo "mal":
Ha colocado la creación del (default)dict
en la declaración en lugar de la configuración. Construir un nuevo defaultdict
es más costoso que un dict
normal, y generalmente ese no es el cuello de botella que debe crear en un programa. Después de todo, construye sus estructuras de datos una vez, pero las usa muchas veces.
Si realiza las pruebas como se muestra a continuación, verá que las operaciones defaultdict
son más rápidas:
>>> import timeit
>>> setup1 = """from collections import defaultdict
... s = [(''yellow'', 1), (''blue'', 2), (''yellow'', 3), (''blue'', 4), (''red'', 1)]
... d = defaultdict(list)"""
>>> stmt1 = """for k, v in s:
... d[k].append(v)"""
>>> setup2 = """s = [(''yellow'', 1), (''blue'', 2), (''yellow'', 3), (''blue'', 4), (''red'', 1)]
... d = {}"""
>>> stmt2 = """for k, v in s:
... d.setdefault(k, []).append(v)"""
>>> timeit.timeit(setup=setup1, stmt=stmt1)
1.0283400125194078
>>> timeit.timeit(setup=setup2, stmt=stmt2)
1.7767367580925395
Python 2.7.3 en Win7 x64.