97 votes

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

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

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 novice en matière de Python et je ne comprends pas bien toutes les questions relatives à la portée de ce langage, mais je ne sais pas pourquoi cet extrait ne fonctionne pas. Avez-vous une idée ?

96voto

Paolo Bergantino Points 199336

Changez cette ligne :

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

A ceci :

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

Regardez 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 déclaration d'importation :

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

31 votes

Ç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 la fonction principal pour qu'il fonctionne.

3 votes

L'espacement des noms en Python est une pure folie pour moi. Je suppose que cela a un sens pour un certain type d'esprit, mais ce type d'esprit n'est pas le mien. Dans mon cas, remercions $DEITY pour Ruby.

5 votes

Womble, c'est une verrue, pas un problème général d'espace de noms en python. Fil conducteur : writeonly.wordpress.com/2008/09/12/ contient des liens vers d'autres discussions à ce sujet.

36voto

user2314737 Points 1671

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

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

Desde el documentation :

Une autre option consiste à passer globals() à la globals paramètre, qui fera en sorte que le code soit exécuté dans votre espace de nom global actuel. Cela peut être plus pratique que de spécifier individuellement imports

21voto

Luka Zakrajšek Points 620

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 votes

Cette astuce est idéale si vous avez besoin d'un code de configuration complexe.

0 votes

Meilleure que l'alternative du code de démarrage donnée dans d'autres réponses (c'est-à-dire meilleure que t = timeit.Timer("foo()", "from __main__ import foo") ). Surtout si vous voulez tester plusieurs fonctions différentes, cela vous évitera de taper beaucoup de texte !

1 votes

J'ai environ 20 importations, donc les passer comme argument devient vite désordonné. Cette astuce est géniale !

8voto

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

Puisque timeit n'a pas votre truc dans la portée.

0voto

mist42nz Points 77

Ajoutez dans votre installation "import thisfile ; "

ensuite, lorsque vous appelez la fonction d'installation myfunc(), utilisez "thisfile.myfunc()".

eg "cefile.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 )

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X