python collections defaultdict setdefault python-collections

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