Das Erhalten des "globalen Namens 'foo' ist nicht definiert" mit Pythons Zeit

89

Ich versuche herauszufinden, wie viel Zeit es dauert, eine Python-Anweisung auszuführen. Deshalb habe ich online nachgesehen und festgestellt, dass die Standardbibliothek ein Modul namens timeit bereitstellt , das genau das vorgibt:

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

Dies führt jedoch zu einem Fehler:

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

Ich bin noch neu in Python und verstehe nicht alle Scoping-Probleme, aber ich weiß nicht, warum dieses Snippet nicht funktioniert. Irgendwelche Gedanken?

Kyle Cronin
quelle

Antworten:

93

Ändern Sie diese Zeile:

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

Dazu:

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

Schauen Sie sich den Link an, den Sie ganz unten angegeben haben.

Um dem timeit-Modul Zugriff auf von Ihnen definierte Funktionen zu gewähren, können Sie einen Setup-Parameter übergeben, der eine import-Anweisung enthält:

Ich habe es gerade auf meinem Computer getestet und es hat mit den Änderungen funktioniert.

Paolo Bergantino
quelle
28
Es klappt! Dies ist jedoch ein ziemlich dummes Schnittstellendesign, wenn ich sowohl den Befehl, den ich zeitlich festlegen möchte, als Zeichenfolge angeben als auch das Hauptmodul importieren muss, damit es funktioniert.
Kyle Cronin
2
Python-Namespace ist für mich völliger Wahnsinn. Ich gehe davon aus, dass es für eine bestimmte Art von Geist Sinn macht, aber diese Art von Geist ist nicht einer, den ich zufällig besitze. Vielen Dank an $ DEITY für Ruby in meinem Fall.
Womble
5
Womble, dies ist eine Warze, kein allgemeines Python-Namespace-Problem. Hauptthread: writeonly.wordpress.com/2008/09/12/… enthält Links zu anderen Diskussionen darüber.
Gregg Lind
1
@ Gregg Der Link ist nicht mehr zugänglich (Fehler 404). Was war in dieser Diskussion?
Ovgolovin
2
Endolith
24

Mit Python 3 können Sie verwenden globals=globals()

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

Aus der Dokumentation :

Eine andere Möglichkeit besteht darin, globals()an den globalsParameter zu übergeben, wodurch der Code in Ihrem aktuellen globalen Namespace ausgeführt wird. Dies kann bequemer sein, als Importe einzeln anzugeben

user2314737
quelle
3
Funktioniert nur für Python 3. globalskein Parameter für Python 2timeit
tony_tiger
21

Sie können diesen Hack versuchen:

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
quelle
1
Dieser Hack ist großartig, wenn Sie sonst komplexen Setup-Code benötigen.
Luís Marques
Besser als die in anderen Antworten angegebene Startcode-Alternative (dh besser als t = timeit.Timer("foo()", "from __main__ import foo")). Insbesondere wenn Sie mehrere verschiedene Funktionen testen möchten, sparen Sie viel Tipparbeit!
A. Sommerh
1
Ich habe ungefähr 20 Importe, daher wird es schnell chaotisch, sie als Argument zu übergeben. Dieser Hack ist großartig!
kramer65
7
Toll! Auf Python3 jedoch benötigen Sie import builtinsund 'eingebaute .__ dikt __. Update (Locals ())'
Greole
Können Sie mehrere Funktionen in der Funktion Time () zeitlich festlegen?
edo101
8
t = timeit.Timer("foo()", "from __main__ import foo")

Da hat timeit deine Sachen nicht im Umfang.

dwc
quelle
0

füge in dein Setup "import thisfile;"

Wenn Sie dann die Setup-Funktion myfunc () aufrufen, verwenden Sie "thisfile.myfunc ()".

zB "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
quelle