Razumevanje i korišćenje Python funkcije timeit
U ovom vodiču, istražićemo kako koristiti funkciju timeit
, koja je deo Pythonovog timeit
modula. Naučićete kako da merite vreme izvršavanja jednostavnih izraza i kompleksnih funkcija u Python okruženju.
Precizno merenje vremena izvršenja vašeg koda omogućava vam da dobijete uvid u performanse različitih delova koda. Ovo je ključno za identifikovanje potencijalnih uskih grla i delova koda koji mogu biti optimizovani za bolje performanse.
Počećemo sa analizom sintakse funkcije timeit
, nakon čega ćemo preći na praktične primere koji će vam pomoći da razumete kako se koristi za merenje vremena izvršenja različitih blokova koda i funkcija unutar vaših Python modula. Hajde da krenemo!
Kako koristiti Python timeit funkciju
Modul timeit
je deo standardne Python biblioteke, što znači da ga možete lako uvesti:
import timeit
Sintaksa za upotrebu funkcije timeit
iz modula timeit
je sledeća:
timeit.timeit(stmt, setup, number)
Gde:
stmt
predstavlja deo koda čije vreme izvršavanja želite da izmerite. Možete ga definisati kao jednostavan Python string, višelinijski string ili poziv funkcije.setup
, kao što samo ime sugeriše, predstavlja deo koda koji se izvršava samo jednom, često kao preduslov za pokretanjestmt
. Na primer, ako merite vreme potrebno za kreiranje NumPy niza, uvoz NumPy-a bi bio deosetup
-a, dok bi samo kreiranje niza bilostmt
.number
definiše koliko puta će sestmt
izvršiti. Po default-u, vrednost je 1 milion (1000000), ali možete podesiti ovaj parametar na bilo koju željenu vrednost.
Sada kada smo se upoznali sa sintaksom funkcije timeit()
, pređimo na praktične primere kodiranja.
Merenje vremena izvršenja jednostavnih Python izraza
U ovom odeljku, fokusiraćemo se na merenje vremena izvršavanja jednostavnih Python izraza koristeći timeit
.
Pokrenite Python REPL i isprobajte sledeće primere koda. U njima merimo vreme izvršavanja operacija stepenovanja i celobrojnog deljenja za 10000 i 100000 iteracija.
Važno je napomenuti da izraz koji želimo da izmerimo prosleđujemo kao Python string i da koristimo tačku i zarez da razdvojimo različite izraze unutar stringa.
>>> import timeit
>>> timeit.timeit('3**4;3//4',number=10000)
0.0004020999999738706
>>> timeit.timeit('3**4;3//4',number=100000)
0.0013780000000451764
Korišćenje Python timeit-a iz komandne linije
timeit
možete koristiti i iz komandne linije. Evo ekvivalentne komandne linije za poziv funkcije timeit
:
$ python -m timeit -n [number] -s [setup] [stmt]
python -m timeit
označava da pokrećemotimeit
kao glavni modul.-n
je opcija komandne linije koja definiše broj puta koliko kod treba da se izvrši, što je ekvivalentno argumentunumber
u funkcijitimeit()
.-s
opcija se koristi za definisanje koda za podešavanje.
Sada ćemo ponoviti prethodni primer koristeći ekvivalent komandne linije:
$ python -m timeit -n 100000 '3**4;3//4'
100000 loops, best of 5: 35.8 nsec per loop
U ovom primeru, merimo vreme izvršavanja ugrađene funkcije len()
. Inicijalizacija stringa je deo koda za podešavanje koji je prosleđen koristeći opciju -s
.
$ python -m timeit -n 100000 -s "string_1 = 'coding'" 'len(string_1)'
100000 loops, best of 5: 239 nsec per loop
Iz izlaza, možete primetiti da dobijamo vreme izvršenja za najbolje od 5 ponavljanja. Šta to znači? Kada pokrenete timeit
iz komandne linije, opcija ponavljanja -r
je po default-u postavljena na 5. To znači da se izvršavanje stmt
za specificiran broj iteracija ponavlja 5 puta, a kao rezultat se vraća najbolje vreme izvršavanja.
Analiza metoda za obrtanje stringova korišćenjem timeit
Prilikom rada sa Python stringovima, često se javlja potreba da se string obrne. Dva najčešće korišćena pristupa za obrtanje stringova su:
- Korišćenje slice-ovanja stringova.
- Korišćenje funkcije
reversed()
i metodejoin()
.
Obrtanje Python stringova korišćenjem slice-ovanja
Hajde da se detaljnije upoznamo sa slice-ovanjem stringova i kako ga možete koristiti da obrnute Python string. Korišćenjem sintakse some-string[start:stop]
, dobijate deo stringa koji počinje na indeksu start
i proteže se do indeksa stop-1
. Pogledajmo jedan primer.
Razmotrimo string ‘Python’. String je dužine 6, a indeksi su od 0, 1, 2 do 5.
>>> string_1 = 'Python'
Kada navedete i početnu i krajnju vrednost, dobićete isečak stringa koji se proteže od start
do stop-1
. Stoga, string_1[1:4]
vraća ‘yth’.
>>> string_1 = 'Python'
>>> string_1[1:4]
'yth'
Kada ne navedete početnu vrednost, koristi se default-na vrednost nula, a isečak počinje od indeksa 0 i proteže se do stop - 1
.
Ovde je vrednost stop 3, tako da slice počinje sa indeksom 0 i ide do indeksa 2.
>>> string_1[:3]
'Pyt'
Kada ne uključite indeks stop
, videćete da isečak počinje od indeksa start
(1) i proteže se do kraja stringa.
>>> string_1[1:]
'ython'
Ignorisanje i početne i krajnje vrednosti vraća isečak celog stringa.
>>> string_1[::]
'Python'
Hajde da kreiramo isečak sa step
vrednošću. Postavimo vrednosti za start
, stop
i step
na 1, 5 i 2. Dobijamo isečak stringa koji počinje od 1 i proteže se do 4 (isključujući krajnju tačku 5) koji sadrži svaki drugi karakter.
>>> string_1[1:5:2]
'yh'
Kada koristite negativan korak, možete dobiti isečak koji počinje na kraju stringa. Sa korakom postavljenim na -2, string_1[5:2:-2]
daje sledeći isečak:
>>> string_1[5:2:-2]
'nh'
Dakle, da bismo dobili obrnutu kopiju stringa, preskačemo početne i krajnje vrednosti i postavljamo korak na -1, kao što je prikazano:
>>> string_1[::-1]
'nohtyP'
Ukratko: string[::-1]
vraća obrnutu kopiju stringa.
Obrtanje stringova korišćenjem ugrađenih funkcija i metoda stringova
Ugrađena funkcija reversed()
u Python-u vraća obrnuti iterator kroz elemente stringa.
>>> string_1 = 'Python'
>>> reversed(string_1)
<reversed object at 0x00BEAF70>
Dakle, možete proći kroz obrnuti iterator koristeći for
petlju:
for char in reversed(string_1):
print(char)
I pristupiti elementima stringa obrnutim redosledom.
# Output
n
o
h
t
y
P
Zatim možete pozvati metodu join()
na obrnutom iteratoru sa sintaksom: <separator>.join(reversed(some-string))
.
Isečak koda ispod prikazuje nekoliko primera gde su separator crtica i razmak, respektivno.
>>> '-'.join(reversed(string1))
'n-o-h-t-y-P'
>>> ' '.join(reversed(string1))
'n o h t y P'
Ovde ne želimo nikakav separator; zato postavite separator na prazan string da biste dobili obrnutu kopiju stringa:
>>> ''.join(reversed(string1))
'nohtyP'
Korišćenje .join(reversed(some-string))
vraća obrnutu kopiju stringa.
Poređenje vremena izvršavanja korišćenjem timeit
Do sada smo naučili dva pristupa za obrtanje Python stringova. Ali koji od njih je brži? Hajde da saznamo.
U prethodnom primeru gde smo merili vreme izvršavanja jednostavnih Python izraza, nismo imali nikakav kod za podešavanje. Ovde obrnemo Python string. Dok se operacija obrtanja stringa izvodi onoliko puta koliko je određeno parametrom number
, kod za podešavanje je inicijalizacija stringa koji će se pokrenuti samo jednom.
>>> import timeit
>>> timeit.timeit(stmt="string_1[::-1]", setup = "string_1 = 'Python'", number = 100000)
0.04951830000001678
>>> timeit.timeit(stmt = "''.join(reversed(string_1))", setup = "string_1 = 'Python'", number = 100000)
0.12858760000000302
Za isti broj ponavljanja za obrtanje datog stringa, pristup slice-ovanjem stringova je brži od korišćenja metode join()
i funkcije reversed()
.
Merenje vremena izvršavanja Python funkcija korišćenjem timeit
U ovom odeljku, naučićemo kako meriti vreme izvršavanja Python funkcija pomoću funkcije timeit
. Razmotrimo funkciju hasDigit
koja, primajući listu stringova kao argument, vraća novu listu stringova koji sadrže barem jednu cifru.
def hasDigit(somelist):
str_with_digit = []
for string in somelist:
check_char = [char.isdigit() for char in string]
if any(check_char):
str_with_digit.append(string)
return str_with_digit
Sada želimo da izmerimo vreme izvršavanja ove Python funkcije hasDigit()
pomoću funkcije timeit
.
Prvo, identifikujemo izraz (stmt
) koji treba da bude vremenski određen. To je poziv funkcije hasDigit()
sa listom stringova kao argumentom. Zatim, definišemo kod za podešavanje (setup
). Da li možete da pogodite šta bi trebalo da bude kod za podešavanje?
Da bi se poziv funkcije uspešno izvršio, kod za podešavanje mora da sadrži:
- Definiciju funkcije
hasDigit()
- Inicijalizaciju liste stringova argumenata.
Definišimo kod za podešavanje u stringu za setup
, kao što je prikazano ispod:
setup = """
def hasDigit(somelist):
str_with_digit = []
for string in somelist:
check_char = [char.isdigit() for char in string]
if any(check_char):
str_with_digit.append(string)
return str_with_digit
thislist=['puffin3','7frost','blue']
"""
Zatim možemo koristiti funkciju timeit
da dobijemo vreme izvršavanja funkcije hasDigit()
za 100000 iteracija.
import timeit
timeit.timeit('hasDigit(thislist)',setup=setup,number=100000)
# Output
0.2810094920000097
Zaključak
Naučili ste kako da koristite Python-ovu funkciju timeit
za merenje vremena izvršavanja izraza, funkcija i drugih poziva. Ovo vam može pomoći da upoređujete svoj kod, analizirate vreme izvršavanja različitih implementacija iste funkcije i još mnogo toga.
Da ponovimo ono što smo naučili u ovom vodiču. Možete koristiti funkciju timeit()
sa sintaksom timeit.timeit(stmt=...,setup=...,number=...)
. Alternativno, možete pokrenuti timeit
iz komandne linije da biste izmerili vreme izvršavanja kraćih isečaka koda.
Kao sledeći korak, možete istražiti kako da koristite druge Python pakete za profiliranje kao što su line-profiler
i memprofiler
za profiliranje koda prema vremenu i memoriji, respektivno.
Nakon toga, možete istražiti kako da izračunate vremensku razliku u Python-u.