Utforska Tidsmätning med Pythons Timeit-modul
Denna handledning ger dig insikter i hur du kan utnyttja timeit-funktionen från Pythons timeit-modul. Du kommer att få kunskapen att mäta exekveringstiden för både enkla uttryck och mer komplexa funktioner i Python.
Genom att mäta din kods exekveringstid kan du få en uppfattning om hur lång tid det tar för olika delar av din kod att köras, vilket hjälper dig att identifiera områden som kan behöva optimeras för bättre prestanda.
Vi inleder med en genomgång av syntaxen för Pythons timeit-funktion. Därefter kommer vi att utforska konkreta exempel för att visa hur du effektivt kan använda den för att mäta exekveringstiden för kodblock och funktioner i dina Python-projekt. Låt oss börja med grunderna.
Använda Timeit-funktionen i Python
Timeit-modulen är en integrerad del av Pythons standardbibliotek, vilket gör den lättillgänglig. För att använda den, behöver du först importera modulen:
import timeit
Den grundläggande strukturen för att använda timeit-funktionen ser ut så här:
timeit.timeit(stmt, setup, number)
Här betyder:
stmt
: Den kodsekvens vars exekveringstid du vill mäta. Detta kan vara en Python-sträng, en flerradssträng, eller namnet på en funktion som ska anropas.setup
: Den kod som förbereder miljön förstmt
, och endast körs en gång. Till exempel, om du mäter hur lång tid det tar att skapa en NumPy-array, kan importen av NumPy vara din setup-kod och skapandet av arrayenstmt
.number
: Antalet gångerstmt
ska exekveras. Standardvärdet är 1 miljon (1000000), men du kan ange ett annat värde efter behov.
Nu när du förstår syntaxen för timeit()
, låt oss utforska några praktiska exempel.
Mäta Exekveringstid för Enkla Python-uttryck
I detta avsnitt ska vi fokusera på att mäta hur lång tid det tar för enkla Python-uttryck att exekvera med hjälp av timeit
.
Starta en Python REPL (Read-Eval-Print Loop) och testa följande exempel. Vi kommer att mäta exekveringstiden för potens- och heltalsdivisionsoperationer för 10 000 respektive 100 000 repetitioner.
Observera att vi skickar in det kodavsnitt som ska mätas som en sträng, där semikolon används för att separera de olika uttrycken i koden.
>>> import timeit
>>> timeit.timeit('3**4;3//4',number=10000)
0.0004020999999738706
>>> timeit.timeit('3**4;3//4',number=100000)
0.0013780000000451764
Användning av Timeit från Kommandoraden
Timeit kan även användas direkt från kommandoraden. Motsvarande kommando för att använda timeit
-funktionen är:
$ python -m timeit -n [number] -s [setup] [stmt]
python -m timeit
: Indikerar att vi användertimeit
som en huvudmodul.-n
: Ett kommandoalternativ som specificerar antalet gånger koden ska köras, motsvarandenumber
-argumentet i funktionentimeit()
.-s
: Används för att definiera den kod som ska köras som förberedelse (setup-koden).
Här är en omskrivning av 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. Initialiseringen av strängen fungerar som setup-kod och anges med -s
-alternativet.
$ python -m timeit -n 100000 -s "string_1 = 'coding'" 'len(string_1)'
100000 loops, best of 5: 239 nsec per loop
Notera att utdata ger exekveringstiden för ”best of 5” runs. Vad betyder det? När du kör timeit
från kommandoraden, är repetitionsalternativet -r
satt till standardvärdet 5. Det innebär att exekveringen av stmt
upprepas fem gånger, och den snabbaste tiden returneras.
Analys av Strängomvändningsmetoder med Timeit
När du hanterar strängar i Python, kan du ibland behöva vända på dem. Det finns två vanliga sätt att vända strängar:
- Genom strängskärning (slicing).
- Genom att använda
reversed()
-funktionen tillsammans medjoin()
-metoden.
Omvänd Strängar med Strängskärning
Låt oss undersöka hur strängskärning fungerar och hur du kan använda den för att vända en sträng. Med syntaxen some-string[start:stop]
skapas en delsträng som börjar vid index start
och sträcker sig fram till stop-1
. Här är ett exempel:
Betrakta strängen ”Python”. Den har längden 6, och indexen är 0, 1, 2, 3, 4 och 5.
>>> string_1 = 'Python'
När du specificerar både start
och stop
, får du en strängskiva som går från start
till stop-1
. Därför, string_1[1:4]
returnerar ”yth”.
>>> string_1 = 'Python'
>>> string_1[1:4]
'yth'
Om du inte specificerar start
-värdet, används 0 som standard. Strängskivan börjar alltså vid index 0 och sträcker sig till stop-1
.
Här är stop
-värdet 3, så skivan börjar vid index 0 och går till index 2.
>>> string_1[:3]
'Pyt'
När du utesluter stop
-indexet, kommer skivan att börja vid start
-indexet (1) och sträcka sig till slutet av strängen.
>>> string_1[1:]
'ython'
Om du ignorerar både start
– och stop
-värdena, kommer hela strängen att returneras.
>>> string_1[::]
'Python'
Låt oss nu skapa en skiva med stegvärdet. Om du sätter start
, stop
, och steget till 1, 5 respektive 2, får vi en skiva av strängen som börjar vid 1, sträcker sig till 4 (exklusive 5), och plockar ut vartannat tecken.
>>> string_1[1:5:2]
'yh'
Med ett negativt steg kan du skapa en skiva som börjar från slutet av strängen. Med ett steg på -2, ger string_1[5:2:-2]
följande skiva:
>>> string_1[5:2:-2]
'nh'
För att få en omvänd kopia av strängen, hoppar vi över start
och stop
, och sätter steget till -1, så här:
>>> string_1[::-1]
'nohtyP'
Sammanfattningsvis: sträng[::-1]
returnerar en omvänd kopia av strängen.
Omvänd Strängar med Inbyggda Funktioner och Strängmetoder
Den inbyggda funktionen reversed()
i Python skapar en omvänd iterator över elementen i strängen.
>>> string_1 = 'Python'
>>> reversed(string_1)
<reversed object at 0x00BEAF70>
Du kan iterera genom den omvända iteratorn med en for-loop:
for char in reversed(string_1):
print(char)
Och på så sätt få tillgång till elementen i strängen i omvänd ordning.
# Output
n
o
h
t
y
P
Därefter kan du anropa join()
-metoden på den omvända iteratorn med syntaxen:
.
Följande kodavsnitt illustrerar 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'
Eftersom vi inte vill ha någon separator, använder vi en tom sträng som avgränsare för att få den omvända kopian 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 undersökt två sätt att vända strängar i Python. Men vilket sätt är snabbast? Låt oss ta reda på det.
I ett tidigare exempel, där vi mätte enkla Python-uttryck, använde vi ingen setup-kod. Här ska vi vända en Python-sträng. Medan omvändningsoperationen körs det antal gånger som anges av number
, är setup-koden 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 är strängskärning snabbare än join()
-metoden i kombination med reversed()
-funktionen.
Mäta Exekveringstid för Python-funktioner med Timeit
I det här avsnittet ska vi utforska hur man mäter exekveringstiden för Python-funktioner med timeit-funktionen. Följande funktion, hasDigit
, tar emot en lista med strängar och returnerar de strängar som innehåller 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 ska vi mäta exekveringstiden för hasDigit()
med timeit
.
Först, identifiera koden (stmt
) som ska tidsbestämmas. Det är anropet av funktionen hasDigit()
med en lista av strängar som argument. Sedan behöver vi definiera setup-koden. Kan du gissa vad den ska vara?
För att anropet av funktionen ska lyckas, måste setup-koden inkludera:
- Definitionen av funktionen
hasDigit()
. - Initialiseringen av listan med strängar.
Här är setup-koden som specificeras i setup
-strängen:
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 mäta exekveringstiden för hasDigit()
-funktionen för 100 000 körningar.
import timeit
timeit.timeit('hasDigit(thislist)',setup=setup,number=100000)
# Output
0.2810094920000097
Sammanfattning
Du har nu lärt dig hur man använder Pythons timeit
-funktion för att mäta exekveringstiden för uttryck, funktioner och andra anropsbara objekt. Detta verktyg kan hjälpa dig att utvärdera din kod, jämföra hastigheten av olika implementeringar av samma funktion, och mer.
Låt oss gå igenom vad vi har lärt oss: du kan använda timeit()
med syntaxen timeit.timeit(stmt=…, setup=…, number=…)
. Alternativt, kan du köra timeit
direkt från kommandoraden för att mäta korta kodavsnitt.
Som nästa steg kan du utforska andra Python-profileringsverktyg som line-profiler
och memprofiler
, som kan hjälpa dig att profilera din kod för tidsåtgång respektive minnesanvändning.
Du kan också lära dig hur man beräknar tidsskillnaden i Python.