2011-09-23 9 views
60

Sto lottando con questo utilizzando timeit e chiedevo se qualcuno avesse qualche consiglioCome usare python timeit quando si passano le variabili alle funzioni?

Fondamentalmente ho una funzione (che mi passa un valore a) che voglio testare la velocità di e ha creato questo:

if __name__=='__main__': 
    from timeit import Timer 
    t = Timer(superMegaIntenseFunction(10)) 
    print t.timeit(number=1) 

ma quando l'eseguo, ottengo errori strani come proveniente dal modulo timeit .:

ValueError: stmt is neither a string nor callable 

Se eseguo la funzione da solo, funziona benissimo. E 'quando lo avvolgo nel tempo in cui è modulo, ottengo gli errori (ho provato ad usare le virgolette doppie e senza..sumero).

qualsiasi suggerimento sarebbe fantastico!

Grazie!

risposta

95

Fai una richiamabile:

if __name__=='__main__': 
    from timeit import Timer 
    t = Timer(lambda: superMegaIntenseFunction(10)) 
    print t.timeit(number=1) 

dovrebbe funzionare

+0

Ha funzionato! Grazie mille. Devo capire che cosa fa la lambda ... sembra che questo abbia fatto la differenza. Grazie Pablo – Lostsoul

+5

se solo questo fosse nella documentazione da qualche parte – endolith

+13

Oh ma lambda aggiunge un po 'di overhead, quindi non è l'ideale per testare piccole cose. 'timeit 5 * 5' è 33 ns mentre' timeit (lambda: 5 * 5)() 'è 233 ns. – endolith

16

Si dovrebbe passare una stringa. cioè

t = Timer('superMegaIntenseFunction(10)','from __main__ import superMegaIntenseFunction') 
+0

Grazie per la risposta oxtopus! non funziona quando lo inserisco tra virgolette, quindi su una stringa ottengo questo errore: NameError: il nome globale 'superMegaIntenseFunction' non è definito. Cos'altro pensi che io possa provare? – Lostsoul

+0

Corretta la risposta per includere l'argomento di installazione. (http: //docs.python.org/library/timeit.html # timeit.Timer) –

21

Timer(superMegaIntenseFunction(10)) significa "chiamata superMegaIntenseFunction(10), quindi passare il risultato a Timer". Questo non è chiaramente quello che vuoi. Timer si aspetta sia un callable (proprio come suona: qualcosa che può essere chiamato, come una funzione), o una stringa (in modo che possa interpretare il contenuto della stringa come codice Python). Timer funziona chiamando ripetutamente la cosa chiamabile e osservando quanto tempo è stato impiegato.

Timer(superMegaIntenseFunction) passerebbe il controllo del tipo, perché superMegaIntenseFunction è richiamabile. Tuttavia, Timer non saprebbe quali valori passare a superMegaIntenseFunction.

Il modo semplice per ovviare a questo, ovviamente, è utilizzare una stringa con il codice. Abbiamo bisogno di passare un argomento 'setup' al codice, perché la stringa è "interpretata come codice" in un nuovo contesto - non ha accesso allo stesso globals, quindi è necessario eseguire un altro bit di codice per rendere definizione disponibile - vedi la risposta di @ oxtopus.

Con lambda (come nella risposta di @ Pablo), è possibile associare il parametro 10 a una chiamata a superMegaIntenseFunction. Tutto quello che stiamo facendo è la creazione di un'altra funzione, che non richiede argomenti e chiama superMegaIntenseFunction con 10. È come se avessi usato def per creare un'altra funzione del genere, tranne per il fatto che la nuova funzione non ottiene un nome (perché non ne ha bisogno).

1

Una nota per i visitatori futuri. Se è necessario per farlo funzionare in pdb debugger e superMegaIntenseFunction non è nel campo di applicazione globale, è possibile farlo funzionare con l'aggiunta di globals:

globals()['superMegaIntenseFunction'] = superMegaIntenseFunction 
timeit.timeit(lambda: superMegaIntenseFunction(x)) 

Note that the timing overhead is a little larger in this case because of the extra function calls. [source]

Problemi correlati