Obtenir «le nom global 'foo' n'est pas défini» avec le timeit de Python

90

J'essaie de savoir combien de temps il faut pour exécuter une instruction Python, alors j'ai regardé en ligne et j'ai trouvé que la bibliothèque standard fournit un module appelé timeit qui prétend faire exactement cela:

import timeit

def foo():
    # ... contains code I want to time ...

def dotime():
    t = timeit.Timer("foo()")
    time = t.timeit(1)
    print "took %fs\n" % (time,)

dotime()

Cependant, cela produit une erreur:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in dotime
  File "/usr/local/lib/python2.6/timeit.py", line 193, in timeit
    timing = self.inner(it, self.timer)
  File "<timeit-src>", line 6, in inner
NameError: global name 'foo' is not defined

Je suis encore nouveau dans Python et je ne comprends pas parfaitement tous les problèmes de portée qu'il a, mais je ne sais pas pourquoi cet extrait de code ne fonctionne pas. Des pensées?

Kyle Cronin
la source

Réponses:

93

Changez cette ligne:

t = timeit.Timer("foo()")

Pour ça:

t = timeit.Timer("foo()", "from __main__ import foo")

Consultez le lien que vous avez fourni tout en bas.

Pour donner au module timeit l'accès aux fonctions que vous définissez, vous pouvez passer un paramètre de configuration qui contient une instruction d'importation:

Je viens de le tester sur ma machine et cela a fonctionné avec les changements.

Paolo Bergantino
la source
28
Ça marche! Cependant, c'est une conception d'interface assez stupide si je dois à la fois fournir la commande que je souhaite chronométrer sous forme de chaîne et importer le module principal pour que cela fonctionne.
Kyle Cronin
2
L'espacement des noms Python est pour moi une folie totale. Je suppose que cela a du sens pour un certain type d'esprit, mais ce genre d'esprit n'est pas celui que je possède. Merci $ DEITY pour Ruby, dans mon cas.
womble
5
womble, c'est une verrue, pas un problème d'espace de noms python général. Le fil de discussion principal: writeonly.wordpress.com/2008/09/12/… a des liens vers d'autres discussions à ce sujet.
Gregg Lind
1
@Gregg Le lien n'est plus accessible (erreur 404). Qu'y avait-il dans cette discussion?
ovgolovin le
2
ces liens sont tous morts
endolith
25

Avec Python 3, vous pouvez utiliser globals=globals()

t = timeit.Timer("foo()", globals=globals())

De la documentation :

Une autre option consiste à passer globals()au globalsparamètre, ce qui entraînera l'exécution du code dans votre espace de noms global actuel. Cela peut être plus pratique que de spécifier individuellement les importations

utilisateur2314737
la source
3
Fonctionne uniquement pour Python 3. globalspas un paramètre pour Python 2timeit
tony_tiger
21

Vous pouvez essayer ce hack:

import timeit

def foo():
    print 'bar'

def dotime():
    t = timeit.Timer("foo()")
    time = t.timeit(1)
    print "took %fs\n" % (time,)

import __builtin__
__builtin__.__dict__.update(locals())

dotime()
Luka Zakrajšek
la source
1
Ce hack est idéal si vous avez besoin d'un code de configuration complexe.
Luís Marques
Mieux que l'alternative au code de démarrage donnée dans d'autres réponses (c'est-à-dire mieux que t = timeit.Timer("foo()", "from __main__ import foo")). Surtout si vous souhaitez tester plusieurs fonctions différentes, cela vous fera économiser beaucoup de frappe!
A.Sommerh
1
J'ai environ 20 importations, donc les passer en argument devient rapidement compliqué. Ce hack est génial!
kramer65
7
Génial! Sur python3 cependant, vous avez besoin import builtinset 'builtins .__ dict __. Update (locals ())'
greole
Pouvez-vous chronométrer plusieurs fonctions dans la fonction Time ()?
edo101 le
8
t = timeit.Timer("foo()", "from __main__ import foo")

Depuis le temps, vos affaires ne sont pas prises en compte.

dwc
la source
0

ajouter dans votre configuration "import thisfile;"

puis lorsque vous appelez la fonction de configuration myfunc (), utilisez "thisfile.myfunc ()"

par exemple "thisfile.py"

def myfunc():

 return 5

def testable(par):

 pass



t=timeit.timeit(stmt="testable(v)",setup="import thisfile; v=thisfile.myfunc();").repeat(10)

print( t )
mist42nz
la source