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?

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.


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


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

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.


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 )
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.