Använda Python Timeit för att tajma din kod

Spread the love

I den här handledningen får du lära dig hur du använder timeit-funktionen från Pythons timeit-modul. Du kommer att lära dig att tajma enkla uttryck och funktioner i Python.

Tajming av din kod kan hjälpa dig att få en uppskattning av exekveringstiden för en kodbit och även identifiera de delar av koden som behöver optimeras.

Vi börjar med att lära oss syntaxen för Pythons timeit-funktion. Och sedan kommer vi att koda exempel för att förstå hur man använder det för att tidsblockera kod och funktioner i din Python-modul. Låt oss börja.

Hur man använder Python timeit-funktionen

Timeit-modulen är en del av Pythons standardbibliotek, och du kan importera den:

import timeit

Syntaxen för att använda timeit-funktionen från timeit-modulen är som visas nedan:

timeit.timeit(stmt, setup, number)

Här:

  • stmt är den kodbit vars exekveringstid ska mätas. Du kan ange det som en enkel Python-sträng eller en flerradssträng, eller skicka in namnet på den anropbara.
  • Som namnet antyder, betecknar setup den bit kod som bara behöver köras en gång, ofta som en förutsättning för att stmt ska köras. Anta till exempel att du beräknar exekveringstiden för skapandet av en NumPy-array. I det här fallet är import av numpy inställningskoden och själva skapandet är det uttalande som ska tidsbestäms.
  • Parameternumret anger antalet gånger stmt körs. Standardvärdet för nummer är 1 miljon (1000000), men du kan också ställa in den här parametern till valfritt annat värde.

Nu när vi har lärt oss syntaxen för att använda timeit()-funktionen, låt oss börja koda några exempel.

Timing av enkla Python-uttryck

I det här avsnittet kommer vi att försöka mäta exekveringstiden för enkla Python-uttryck med timeit.

Starta en Python REPL och kör följande kodexempel. Här beräknar vi exekveringstiden för exponentierings- och våningsindelningsoperationer för 10 000 och 100 000 körningar.

Lägg märke till att vi skickar in satsen som ska tidsstyras som en Python-sträng och använder semikolon för att separera de olika uttrycken i satsen.

>>> import timeit
>>> timeit.timeit('3**4;3//4',number=10000)
0.0004020999999738706

>>> timeit.timeit('3**4;3//4',number=100000)
0.0013780000000451764

Kör Python timeit på kommandoraden

Du kan också använda timeit på kommandoraden. Här är kommandoradens motsvarighet till timeit-funktionsanropet:

$ python-m timeit -n [number] -s [setup] [stmt]
  • python -m timeit representerar att vi kör timeit som huvudmodul.
  • n är ett kommandoradsalternativ som anger hur många gånger koden ska köras. Detta motsvarar nummerargumentet i funktionsanropet timeit().
  • Du kan använda alternativen -s för att definiera inställningskoden.
  10 bästa molnvärdplattformar för start till stora organisationer

Här skriver vi om det föregående exemplet med kommandoradens motsvarighet:

$ python -m timeit -n 100000 '3**4;3//4'
100000 loops, best of 5: 35.8 nsec per loop

I det här exemplet beräknar vi exekveringstiden för den inbyggda len()-funktionen. Initieringen av strängen är inställningskoden som skickas in med s-alternativet.

$ python -m timeit -n 100000 -s "string_1 = 'coding'" 'len(string_1)'
100000 loops, best of 5: 239 nsec per loop

Lägg märke till att vi får exekveringstiden för bäst av 5 körningar i utgången. Vad betyder det här? När du kör timeit på kommandoraden sätts upprepningsalternativet r till standardvärdet 5. Detta innebär att exekveringen av stmt för det angivna antalet gånger upprepas fem gånger, och den bästa av exekveringstiderna returneras.

Analys av strängomvändningsmetoder med timeit

När du arbetar med Python-strängar kanske du vill vända på dem. De två vanligaste metoderna för att vända strängar är följande:

  • Med hjälp av skärning av snöre
  • Använda reversed()-funktionen och join()-metoden

Omvänd Python-strängar med strängskivning

Låt oss gå igenom hur skärning av strängar fungerar och hur du kan använda den för att vända en Python-sträng. Använder syntaxen some-string[start:stop] returnerar en del av strängen som börjar vid indexstarten och sträcker sig upp till indexstopp-1. Låt oss ta ett exempel.

Tänk på följande sträng ’Python’. Strängen har längden 6 och listan med index är 0, 1, 2 upp till 5.

>>> string_1 = 'Python'

När du anger både start- och stoppvärden får du en strängskiva som sträcker sig från start till stopp-1. Därför, string_1[1:4] returnerar ’yth’.

>>> string_1 = 'Python'
>>> string_1[1:4]
'yth'

När du inte anger startvärdet används standardstartvärdet noll, och skivan börjar vid index noll och sträcker sig upp till stopp – 1.

Här är stoppvärdet 3, så skivan börjar vid index 0 och går upp till index 2.

>>> string_1[:3]
'Pyt'

När du inte inkluderar stoppindexet ser du att segmentet börjar från startindexet (1) och sträcker sig upp till slutet av strängen.

  Hur du konverterar ditt befintliga Amazon Echo till Kid's Edition

>>> string_1[1:]
'ython'

Om du ignorerar både start- och stoppvärdena returneras en del av hela strängen.

>>> string_1[::]
'Python'

Låt oss skapa en skiva med stegvärdet. Ställ in start-, stopp- och stegvärdena till 1, 5 respektive 2. Vi får en bit av strängen som börjar vid 1 som sträcker sig upp till 4 (exklusive slutpunkt 5) som innehåller vartannat tecken.

>>> string_1[1:5:2]
'yh'

När du använder ett negativt steg kan du få en skiva som börjar i slutet av strängen. Med steget satt till -2, string_1[5:2:-2] ger följande skiva:

>>> string_1[5:2:-2]
'nh'

Så för att få en omvänd kopia av strängen hoppar vi över start- och stoppvärdena och ställer in steget till -1, som visas:

>>> string_1[::-1]
'nohtyP'

Sammanfattningsvis: sträng[::-1] returnerar en omvänd kopia av strängen.

Omvända strängar med inbyggda funktioner och strängmetoder

Den inbyggda reversed()-funktionen i Python kommer att returnera en omvänd iterator över elementen i strängen.

>>> string_1 = 'Python'
>>> reversed(string_1)
<reversed object at 0x00BEAF70>

Så du kan loopa genom den omvända iteratorn med en for-loop:

for char in reversed(string_1):
    print(char)

Och komma åt elementen i strängen i omvänd ordning.

# Output
n
o
h
t
y
P

Därefter kan du anropa metoden join() på den omvända iteratorn med syntaxen: .join(reversed(some-string)).

Kodavsnittet nedan visar ett par exempel där avgränsaren är ett bindestreck respektive ett blanksteg.

>>> '-'.join(reversed(string1))
'n-o-h-t-y-P'
>>> ' '.join(reversed(string1))
'n o h t y P'

Här vill vi inte ha någon separator; så ställ in avgränsaren till en tom sträng för att få en omvänd kopia av strängen:

>>> ''.join(reversed(string1))
'nohtyP'

Att använda ”.join(reversed(some-string)) returnerar en omvänd kopia av strängen.

Jämföra exekveringstider med timeit

Hittills har vi lärt oss två metoder för att vända Python-strängar. Men vilken av dem är snabbare? Låt oss ta reda på.

I ett tidigare exempel där vi timade enkla Python-uttryck, hade vi ingen inställningskod. Här vänder vi om Python-strängen. Medan strängvändningsoperationen körs under det antal gånger som anges av numret, är installationskoden initialiseringen av strängen som bara körs en gång.

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

För samma antal körningar för att vända den givna strängen är strängdelningsmetoden snabbare än att använda join()-metoden och reversed()-funktionen.

  13 bästa spelinspelningsprogram för att fånga spel

Timing Python-funktioner Använder timeit

I det här avsnittet, låt oss lära oss hur man tidsbestämmer Python-funktioner med timeit-funktionen. Med en lista med strängar, returnerar följande funktion hasDigit listan med strängar som har minst en siffra.

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

Nu skulle vi vilja mäta exekveringstiden för denna Python-funktion hasDigit() med timeit.

Låt oss först identifiera påståendet som ska tidsinställas (stmt). Det är anropet till funktionen hasDigit() med en lista med strängar som argument. Låt oss sedan definiera inställningskoden. Kan du gissa vad inställningskoden ska vara?

För att funktionsanropet ska köras framgångsrikt bör installationskoden innehålla följande:

  • Definitionen av funktionen hasDigit()
  • Initieringen av argumentlistan med strängar

Låt oss definiera inställningskoden i installationssträngen, som visas nedan:

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']
     """

Därefter kan vi använda timeit-funktionen och få exekveringstiden för hasDigit()-funktionen för 100 000 körningar.

import timeit
timeit.timeit('hasDigit(thislist)',setup=setup,number=100000)
# Output
0.2810094920000097

Slutsats

Du har lärt dig hur du använder Pythons timeit-funktion för att tidsstyra uttryck, funktioner och andra anropsbara. Detta kan hjälpa dig att jämföra din kod, jämföra körtiderna för olika implementeringar av samma funktion och mer.

Låt oss granska vad vi har lärt oss i den här handledningen. Du kan använda timeit()-funktionen med syntaxen timeit.timeit(stmt=…,setup=…,number=…). Alternativt kan du köra timeit på kommandoraden för att tidsstyra korta kodavsnitt.

Som ett nästa steg kan du utforska hur du använder andra Python-profileringspaket som line-profiler och memprofiler för att profilera din kod för tid respektive minne.

Lär dig sedan hur du beräknar tidsskillnaden i Python.