2011-02-23 8 views
23

Este es el esquema de un programa sencillocómo pasar parámetros de una función cuando se utiliza timeit.Timer()

# some pre-defined constants 
A = 1 
B = 2 

# function that does something critical 
def foo(num1, num2): 
    # do something 

# main program.... do something to A and B 
for i in range(20): 
    # do something to A and B 
    # and update A and B during each iteration 

import timeit 
t = timeit.Timer(stmt="foo(num1,num2)") 
print t.timeit(5) 

cada vez me siento "nombre global foo no está definido" ..... ¿Puede alguien ayudarme con esto? ¡Gracias!

+0

Bueno, antes que nada, la sangría aquí es confusa. Parece que 'foo' se está definiendo en un ámbito diferente que' t' ... – senderle

+0

hi. arreglé la sangría se ve mejor ahora? :] Gracias. – CppLearner

+0

timeit está bien para frases sencillas, pero para cualquier otra cosa mejor, compruebe este método http://stackoverflow.com/questions/5478351/python-time-measure-function – vincent

Respuesta

8

Los fragmentos de código deben ser independientes: no pueden hacer referencias externas. Debe definir los valores de la cuenta de cuerdas o la configuración de cuerdas:

import timeit 

setup = """ 
A = 1 
B = 2 

def foo(num1, num2): 
    pass 

def mainprog(): 
    global A,B 
    for i in range(20): 
     # do something to A and B 
     foo(A, B) 
""" 

t = timeit.Timer(stmt="mainprog()" setup=setup) 
print(t.timeit(5)) 

Mejor aún, vuelve a escribir el código para no utilizar los valores globales.

+0

¡gracias! ¡entiendo completamente! ;] – CppLearner

+2

La respuesta de Lucas S. hace que este se sienta un poco mal. Torpe al menos. –

9

Su función debe definirse en la cadena de configuración. Una buena manera de hacerlo es mediante la creación de su código en un módulo, por lo que tiene que hacer sencilla

t = timeit.Timer("foo(num1, num2)", "from myfile import foo") 
t.timeit(5) 

De lo contrario, tendrá que definir toda la configuración como una cadena dentro de la frase de preparación.

setup = """ 
# some pre-defined constants 
A = 1 
B = 2 

# function that does something critical 
def foo(num1, num2): 
    # do something 

# main program.... do something to A and B 
for i in range(20): 
    # do something to A and B 
    # and update A and B during each iteration 
""" 

t = timeit.Timer("foo(num1, num2)", setup) 
t.timeit(5) 

Algo sorprendente que acabo de descubrir es un atajo para iPython que usa cProfile.

def foo(x, y): 
    print x*y 

%prun foo("foo", 100) 
12

Suponiendo que el nombre de archivo de módulo es test.py

# some pre-defined constants 
A = 1 
B = 2 

# function that does something critical 
def foo(n, m): 
    pass 

# main program.... do something to A and B 
for i in range(20): 
    pass 

import timeit 
t = timeit.Timer(stmt="test.foo(test.A, test.B)", setup="import test") 
print t.timeit(5) 
8

por lo general creo una función adicional:

def f(x,y): 
    return x*y 

v1 = 10 
v2 = 20 

def f_test(): 
    f(v1,v2) 

print(timeit.timeit("f_test()", setup="from __main__ import f_test")) 
+0

funciona solo si 'v1' y' v2' son globales. Si son locales para la función f no funciona – Kyrol

17

Las funciones se pueden utilizar argumentos en timeit si éstas se crean mediante cierres , podemos agregar estos comportamientos envolviéndolos en otra función.

def foo(num1, num2): 
    def _foo(): 
     # do something to num1 and num2 
     pass 
    return _foo 

A = 1 
B = 2 

import timeit 
t = timeit.Timer(foo(A,B)) 
print t.timeit(5) 

o más corto, podemos utilizar functools.partial en lugar de cierres explícitas de declaración

def foo(num1, num2): 
    # do something to num1 and num2 
    pass 

A = 1 
B = 2 

import timeit, functools 
t = timeit.Timer(functools.partial(foo, A, B)) 
print t.timeit(5) 
+2

Gracias, functools me ayudó a evitar los globales, el enfoque de cadena desagradable y el negocio de decorador/cierre. – jatal

1

Aquí está un ejemplo de cómo compartimentar la rutina de temporización, sin globales que llaman

def foo(a, b): 
    '''Do something to `a` and `b`''' 
    return a + b 

def time_foo(): 
    '''Create timer object simply without using global variables''' 
    import timeit 

    _foo = foo 
    a = 1 
    b = 2 

    # Get `Timer` oject, alternatively just get time with `timeit.timeit()` 
    t = timeit.Timer('_foo(a, b)', globals=locals()) 

    return t 

Usted podría incluso generalice esto si quiere usar la misma función timeit para sincronizar otras funciones. He aquí un ejemplo con su ejemplo main() rutina:

def foo1(a, b): 
    '''Add `a` and `b`''' 
    return a + b 

def foo2(a, b): 
    '''More math on `a` and `b`''' 
    return (a**2 * b)**2 

def time_foo(func, **kwargs): 
    '''Create timer object simply without using global variables''' 
    import timeit 
    return timeit.timeit('func(**kwargs)', globals=locals()) 

def run(): 
    '''Modify inputs to foo and see affect on execution time''' 

    a = 1 
    b = 2 
    for i in range(10): 
     # Update `a` and `b` 
     a += 1 
     b += 2 
     # Pass args to foo as **kwargs dict 
     print('foo1 time: ', time_foo(foo1, **{'a':a, 'b':b})) 
     print('foo2 time: ', time_foo(foo2, **{'a':a, 'b':b})) 

    return None 
0

Yo prefiero crear una clase static con todo listo los datos para ser recogidos antes de ejecutar el temporizador.

Otra nota, es mejor que hacer pruebas de funcionamiento de la función en lugar de en el espacio global, ya que el espacio global no se está aprovechando de FAST_LOADWhy does Python code run faster in a function?

class Data(object): 
    """Data Creation""" 
    x = [i for i in range(0, 10000)] 
    y = tuple([i for i in range(0, 10000)]) 
    def __init__(self): 
     pass 

import timeit 

def testIterator(x): 
    for i in range(10000): 
     z = i 


print timeit.timeit("testIterator(Data.x)", setup="from __main__ import testIterator, Data", number=50) 
print timeit.timeit("testIterator(Data.y)", setup="from __main__ import testIterator, Data", number=50) 
0

Esto debería funcionar:

import timeit 

def f(x,y): 
    return x*y 

x = 5 
y = 7 

print(timeit.timeit(stmt='f(x,y)', 
        setup='from __main__ import f, x, y', 
        number=1000)) 
Cuestiones relacionadas