Uzyskanie „globalnej nazwy 'foo' nie jest zdefiniowane” w czasie Pythona

92

Próbuję dowiedzieć się, ile czasu zajmuje wykonanie instrukcji w języku Python, więc spojrzałem w Internecie i stwierdziłem, że standardowa biblioteka zawiera moduł o nazwie timeit, który ma dokładnie to robić:

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

Jednak powoduje to błąd:

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

Wciąż jestem nowy w Pythonie i nie rozumiem w pełni wszystkich problemów związanych z zakresem, ale nie wiem, dlaczego ten fragment nie działa. jakieś pomysły?

Kyle Cronin
źródło

Odpowiedzi:

93

Zmień tę linię:

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

Do tego:

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

Sprawdź link, który podałeś na samym dole.

Aby dać modułowi timeit dostęp do zdefiniowanych funkcji, możesz przekazać parametr setup, który zawiera instrukcję importu:

Właśnie przetestowałem to na moim komputerze i działało ze zmianami.

Paolo Bergantino
źródło
28
To działa! Jest to jednak dość głupi projekt interfejsu, jeśli muszę zarówno podać polecenie, które chcę ustawić w postaci ciągu, jak i zaimportować główny moduł, aby działał.
Kyle Cronin
2
Przestrzenie nazw w Pythonie są dla mnie kompletnym szaleństwem. Zakładam, że ma to sens dla pewnego rodzaju umysłu, ale nie mam takiego umysłu. Dziękuję $ DEITY za Ruby, w moim przypadku.
womble
5
womble, to jest brodawka, a nie ogólny problem z przestrzenią nazw Pythona. Główny wątek: writeonly.wordpress.com/2008/09/12/ ... zawiera linki do innych dyskusji na ten temat.
Gregg Lind
1
@Gregg Link nie jest już dostępny (błąd 404). Co było w tej dyskusji?
ovgolovin
2
wszystkie te linki są martwe
endolit
25

W Pythonie 3 możesz używać globals=globals()

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

Z dokumentacji :

Inną opcją jest przejście globals()doglobals parametru, co spowoduje wykonanie kodu w bieżącej globalnej przestrzeni nazw. Może to być wygodniejsze niż indywidualne określanie importu

user2314737
źródło
3
Działa tylko z Pythonem 3. globalsnie jest parametrem dla Pythona 2timeit
tony_tiger
21

Możesz spróbować tego hacka:

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
źródło
1
Ten hack jest świetny, jeśli w przeciwnym razie potrzebujesz złożonego kodu konfiguracji.
Luís Marques
Lepsze niż alternatywa kodu startowego podana w innych odpowiedziach (tj. Lepsza niż t = timeit.Timer("foo()", "from __main__ import foo")). Szczególnie, jeśli chcesz przetestować kilka różnych funkcji, zaoszczędzi to dużo pisania!
A.Sommerh
1
Mam około 20 importów, więc przekazywanie ich jako argumentów szybko się komplikuje. Ten hack jest niesamowity!
kramer65
7
Świetny! Jednak na python3 potrzebujesz import builtinsi 'builtins .__ dict __. Update (locals ())'
greole
Czy można mierzyć czas dla wielu funkcji w funkcji Time ()?
edo101
8
t = timeit.Timer("foo()", "from __main__ import foo")

Ponieważ czas nie obejmuje twoich rzeczy.

dwc
źródło
0

dodaj do swojej konfiguracji "import thisfile;"

wtedy gdy wywołasz funkcję setup myfunc () użyj "thisfile.myfunc ()"

np. „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
źródło