Python: ¿hay una manera de importar una variable usando timeit.timeit ()?

Supongamos que tengo alguna función que toma una matriz y cambia cada elemento a 0.

def function(array): for i in range(0,len(array)): array[i] = 0 return array 

Quiero probar cuánto tiempo tarda esta función en ejecutarse en una matriz aleatoria, que deseo generar FUERA de la prueba de timeit. En otras palabras, no quiero incluir el tiempo que toma generar la matriz en el tiempo.

Primero almaceno una matriz aleatoria en una variable x y hago:

 timeit.timeit("function(x)",setup="from __main__ import function") 

Pero esto me da un error: NameError: el nombre global ‘x’ no está definido

¿Cómo puedo hacer esto?

Importar x desde __main__ también :

 timeit.timeit("function(x)", setup="from __main__ import function, x") 

Al igual que la function , x es un nombre en el módulo __main__ , y se puede importar a la configuración de timeit .

Puede evitar este problema por completo si pasa timeit una función en lugar de una cadena. En ese caso, la función se ejecuta en su entorno global normal y de cierre. Asi que:

 timeit.timeit(lambda: function(x)) 

O, si lo prefieres:

 timeit.timeit(partial(function, x)) 

(Consulte aquí para obtener más detalles. Tenga en cuenta que requiere Python 2.6+, por lo que si necesita 2.3-2.5, no puede usar este truco).


Como dice la documentación, “Tenga en cuenta que la sobrecarga de tiempo es un poco mayor en este caso debido a las llamadas de función extra”.

Esto significa que hace que el timeit se ejecute más lento. Por ejemplo:

 >>> def f(): pass >>> timeit.timeit('timeit.timeit("f()", setup="from __main__ import f")', setup='import timeit', number=1000) 91.66315175301861 >>> timeit.timeit(lambda: timeit.timeit(f), number=100) 94.89793294097762 

Sin embargo, no afecta los resultados reales:

 >>> timeit.timeit(f, number=100000000) 8.81197881908156 >>> timeit.timeit('f()', setup='from __main__ import f', number=100000000) 8.893913001054898 

(En los casos excepcionales en que lo hace, eso generalmente significa que una versión u otra no estaba probando la función de la forma en que se llamaría en su código real, o estaba probando el cierre incorrecto o similar).

Tenga en cuenta que el tiempo real tomado dentro de la función aquí es de aproximadamente 88 segundos, por lo que casi hemos duplicado la sobrecarga del código de tiempo … pero aún así solo se ha agregado un 3% al tiempo total de prueba. Y cuanto menos trivial sea, menor será esta diferencia.

Importar x desde __main__ :

 timeit.timeit("function(x)",setup="from __main__ import function, x") 

Alternativamente, puede agregar x a los globals . Lo bueno de esto es que funciona en una sesión de depuración de pdb :

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

Tenga en cuenta que la sobrecarga de tiempo es un poco mayor en este caso debido a las llamadas a funciones adicionales. [fuente]

Con Python 3.5, se ha introducido el argumento opcional globals . Permite especificar el espacio de nombres en el que se ejecutará la instrucción timeit.

Así que en lugar de escribir:

timeit.timeit("function(x), setup="from __main__ import function, x")

… ahora puedes escribir:

timeit.timeit("function(x)", globals=globals())