web-dev-qa-db-fra.com

comment passer les paramètres d'une fonction en utilisant timeit.Timer ()

C'est le contour d'un programme simple

# 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)

Je continue juste à obtenir "le nom global foo n'est pas défini" ..... Quelqu'un peut-il m'aider? Merci!

34
CppLearner

Les extraits de code doivent être autonomes. Ils ne peuvent pas faire de références externes. Vous devez définir vos valeurs dans la chaîne d'instructions ou la chaîne d'installation:

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))

Mieux encore, réécrivez votre code pour ne pas utiliser de valeurs globales.

11
Hugh Bothwell

Les fonctions peuvent utiliser des arguments dans timeit s'ils sont créés à l'aide de fermetures, nous pouvons ajouter ces comportements en les encapsulant dans une autre fonction.

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)

ou plus court, nous pouvons utiliser functools.partial au lieu de la déclaration de fermetures explicites

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)
33

En supposant que votre nom de fichier de module est 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)
13
Lucas S.

Votre fonction doit être définie dans la chaîne de configuration. Un bon moyen de le faire est de configurer votre code dans un module, il vous suffit donc de le faire. 

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

Sinon, vous devrez définir toute la configuration en tant que chaîne à l'intérieur de l'instruction de configuration.

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)

Quelque chose de génial que je viens de découvrir est un raccourci pour iPython qui utilise cProfile.

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

%prun foo("foo", 100)
9
Yuji 'Tomita' Tomita

Je crée généralement une fonction supplémentaire:

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"))
8
Vinicius Veroneze

Voici un exemple montrant comment compartimenter la routine de chronométrage sans appeler de globales

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

Vous pouvez même généraliser ceci si vous souhaitez utiliser la même fonction timeit pour chronométrer d'autres fonctions. Voici un exemple avec votre exemple de routine main():

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
1
ryanjdillon

Je jouais avec la synchronisation dans Python 3.7 aujourd'hui et j'essayais de transmettre des fonctions et des variables à la minuterie. C'est ce que je suis venu avec.

import re

text = "This         is      a  test of the      emergency broadcast       system"

def regex(text):
    return re.sub(r"(\s)\1{1,}", r"\1", text)

def loop_while(text):
    if "  " in text:
        while "  " in text:
            text = text.replace("  ", " ")

    return text

if __== "__main__":
    import timeit

    callable_functions = [item for item in locals().items() if callable(item[1])]

    for func_name, func in callable_functions:
        elapsed_time = timeit.timeit(f"{func_name}(text)", globals=globals(), number=100000)
        print(f"{func_name}: {elapsed_time} \n{func(text)}\n")

Cela génère:

regex: 1.378352418
Ceci est un test du système de diffusion d'urgence

loop_while: 0.15858950299999997
Ceci est un test de l'urgence système de diffusion

Il suffit ensuite de tester une nouvelle version pour ajouter une nouvelle fonction. Quelque chose comme:

def split_join(text):
    return " ".join(text.split())

Maintenant, il affiche:

regex: 1.378352418
Ceci est un test du système de diffusion d'urgence

loop_while: 0.15858950299999997
Ceci est un test du système de diffusion d'urgence

split_join: 0.05700970800000005
Ceci est un test du système de diffusion d'urgence

0
GollyJer

Cela devrait fonctionner:

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))
0
foo bar

Je préfère créer une classe static avec toutes les données prêtes à être récupérées avant l'exécution du chronomètre. 

Autre remarque, il est préférable d'effectuer des tests en mode fonctionnel plutôt qu'en espace global, l'espace global ne tirant pas parti de FAST_LOADPourquoi le code Python s'exécute-t-il plus rapidement dans une fonction?

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
user1767754