Comment passer les paramètres d'une fonction en utilisant timeit.Minuterie()

voici les grandes lignes 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 continuer à recevoir "nom global foo n'est pas défini"..... Quelqu'un peut-il m'aider sur ce point? Merci!

30
demandé sur CppLearner 2011-02-23 05:36:15

10 réponses

les extraits de code doivent être indépendants-ils ne peuvent pas faire de références externes. Vous devez définir vos valeurs dans l'instruction-string ou setup-string:

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
répondu Hugh Bothwell 2011-02-23 02:46:31

les fonctions peuvent utiliser des arguments dans timeit si ceux-ci sont créés en utilisant des fermetures, nous pouvons ajouter ces comportements en les enveloppant 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.partie au lieu de la déclaration de fermeture explicite

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)
27
répondu Jose Ricardo Bustos M. 2015-09-14 15:11:18

supposons que votre nom de fichier module soit 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
répondu Lucas S. 2011-02-23 02:56:14

votre fonction doit être définie dans la chaîne de configuration. Une bonne façon de le faire est de configurer votre code dans un module, donc vous devez simplement faire

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

sinon, vous devrez définir toute la configuration comme une chaîne à l'intérieur de la déclaration setup.

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
répondu Yuji 'Tomita' Tomita 2011-02-23 02:48:00

je crée habituellement 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
répondu Vinicius Veroneze 2013-08-25 23:20:08

voici un exemple pour compartimenter la routine temporelle, sans appeler les globals

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 cela si vous voulez utiliser la même fonction timeit pour chronométrer d'autres fonctions. Voici un exemple avec votre exemple main() routine:

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
répondu ryanjdillon 2017-06-28 12:20:24

il y a une solution beaucoup plus simple (au moins pour Python 3), vous pouvez faire exécuter le code dans votre espace de noms global actuel:

t = timeit.Timer(stmt="foo(num1,num2)", globals=globals())

https://docs.python.org/3/library/timeit.html#examples Je sais que les globals ne sont pas préférés, mais si vous faites juste un script rapide pour vérifier quelque chose, je pense que c'est l'implémentation la plus facile.

1
répondu RustyToms 2018-08-18 23:12:52

je préfère créer une classe static avec toutes les données prêtes à être récupérées avant d'exécuter le minuteur.

une autre note, il est préférable de faire des essais en fonction plutôt que dans l'espace global, car l'espace global ne profite pas de FAST_LOAD pourquoi 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
répondu user1767754 2017-12-08 01:12:06

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
répondu foo bar 2018-01-13 20:10:24

je jouais avec le timing en python 3.7 aujourd'hui et j'essayais de passer des fonctions et des variables dans 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,}", r"", text)

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

    return text

if __name__ == "__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")

Ce sorties:

regex: 1.378352418

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

loop_while: 0.1589502999997
151990920" Ceci est un test de l'urgence système de diffusion

tout ce qu'il faut pour tester une nouvelle version est l'ajout d'une nouvelle fonction. Quelque chose comme:

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

Maintenant, c'sorties:

regex: 1.378352418

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

loop_while: 0.1589502999997
151990920" 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
répondu GollyJer 2018-09-23 18:46:30