2009-03-17 10 views
10

Primero, soy nuevo en Python, entonces me disculpo si he pasado por alto algo, pero me gustaría usar dict.fromkeys (o algo similar) para crear un diccionario de listas, cuyas claves se proporcionan en otra lista. Estoy realizando algunas pruebas de tiempo y me gustaría que la clave sea la variable de entrada y que la lista incluya los tiempos de las carreras:¿Cómo creo un valor único para cada clave usando dict.fromkeys?

def benchmark(input): 
    ... 
    return time_taken 

runs = 10 
inputs = (1, 2, 3, 5, 8, 13, 21, 34, 55) 
results = dict.fromkeys(inputs, []) 

for run in range(0, runs): 
    for i in inputs: 
     results[i].append(benchmark(i)) 

El problema que estoy teniendo es que todas las llaves el diccionario parece compartir la misma lista, y cada ejecución simplemente se agrega a ella. ¿Hay alguna manera de generar una lista vacía única para cada clave usando fromkeys? Si no, ¿hay otra forma de hacer esto sin generar el diccionario resultante a mano?

Respuesta

10

El problema es que en

results = dict.fromkeys(inputs, []) 

[] se evalúa sólo una vez, allí mismo.

me gustaría volver a escribir el código de esa manera:

runs = 10 
inputs = (1, 2, 3, 5, 8, 13, 21, 34, 55) 
results = {} 

for run in range(runs): 
    for i in inputs: 
     results.setdefault(i,[]).append(benchmark(i)) 

Otra opción es:

runs = 10 
inputs = (1, 2, 3, 5, 8, 13, 21, 34, 55) 
results = dict([(i,[]) for i in inputs]) 

for run in range(runs): 
    for i in inputs: 
     results[i].append(benchmark(i)) 
+0

¡Impresionante, eso funciona muy bien! ¡Gracias! (aunque desearía que fuera posible generar las listas vacías antes de que tuviera que usarlas) –

+0

No es posible. Una vez que llama a [] o list(), se crea un objeto y se enlaza a la variable. Vea por ejemplo esto x = [[]] * 10; x [0] .append ('test'); imprimir x – vartec

+0

Ok, ahí tienes una alternativa con toda la lista instanciada. – vartec

12

Consulte defaultdict (requiere Python 2.5 o posterior).

from collections import defaultdict 

def benchmark(input): 
    ... 
    return time_taken 

runs = 10 
inputs = (1, 2, 3, 5, 8, 13, 21, 34, 55) 
results = defaultdict(list) # Creates a dict where the default value for any key is an empty list 

for run in range(0, runs): 
    for i in inputs: 
     results[i].append(benchmark(i)) 
+0

Eso también funciona bien - solo deseo que sea un diccionario "real", no una clase que pretende ser uno. –

+0

Para ser justos, es una subclase con cambios mínimos, por lo que "pretender ser uno" parece un poco fuerte. –

+0

+1 Es la manera de hacerlo si está seguro de que no tendrá que usar su código con Python <2.5. (Recientemente he buscado ofertas de alojamiento, y aún hay muchas que usan Python 2.4). – vartec

2

También puede hacer esto si usted no quiere aprender nada nuevo (aunque recomiendo ¡lo haces!) Tengo curiosidad sobre qué método es más rápido?

results = dict.fromkeys(inputs) 

for run in range(0, runs): 
    for i in inputs: 
     if not results[i]: 
      results[i] = [] 
     results[i].append(benchmark(i)) 
Cuestiones relacionadas