Коришћење Питхон Тимеит-а за време вашег кода

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 pokretanje stmt. Na primer, ako merite vreme potrebno za kreiranje NumPy niza, uvoz NumPy-a bi bio deo setup-a, dok bi samo kreiranje niza bilo stmt.
  • number definiše koliko puta će se stmt 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ćemo timeit kao glavni modul.
  • -n je opcija komandne linije koja definiše broj puta koliko kod treba da se izvrši, što je ekvivalentno argumentu number u funkciji timeit().
  • -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 metode join().

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.