Použití Python Timeit k načasování vašeho kódu

V tomto tutoriálu se naučíte používat funkci timeit z modulu timeit v Pythonu. Naučíte se časovat jednoduché výrazy a funkce v Pythonu.

Načasování kódu vám může pomoci získat odhad doby provedení části kódu a také identifikovat části kódu, které je třeba optimalizovat.

Začneme tím, že se naučíme syntaxi funkce timeit v Pythonu. A pak napíšeme příklady kódu, abychom pochopili, jak jej použít k načasování bloků kódu a funkcí ve vašem modulu Python. Pojďme začít.

Jak používat funkci timeit v Pythonu

Modul timeit je součástí standardní knihovny Pythonu a můžete jej importovat:

import timeit

Syntaxe pro použití funkce timeit z modulu timeit je uvedena níže:

timeit.timeit(stmt, setup, number)

Tady:

  • stmt je kus kódu, jehož doba provádění se má měřit. Můžete jej zadat jako jednoduchý řetězec Pythonu nebo jako víceřádkový řetězec nebo předat název volatelné položky.
  • Jak název napovídá, setup označuje kus kódu, který je třeba spustit pouze jednou, často jako předpoklad pro spuštění stmt. Předpokládejme například, že počítáte dobu provádění pro vytvoření pole NumPy. V tomto případě je import numpy kód nastavení a skutečné vytvoření je příkaz, který má být načasován.
  • Číslo parametru udává, kolikrát se stmt spustí. Výchozí hodnota čísla je 1 milion (1 000 000), ale tento parametr můžete také nastavit na jakoukoli jinou hodnotu podle vašeho výběru.

Nyní, když jsme se naučili syntaxi pro použití funkce timeit(), začněme kódovat některé příklady.

Časování jednoduchých výrazů v Pythonu

V této části se pokusíme změřit dobu provádění jednoduchých výrazů Pythonu pomocí timeit.

Spusťte Python REPL a spusťte následující příklady kódu. Zde počítáme dobu provádění operací umocňování a dělení na 10 000 a 100 000 běhů.

Všimněte si, že v příkazu, který má být načasován, předáváme jako řetězec Pythonu a k oddělení různých výrazů v příkazu používáme středník.

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

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

Spuštění Pythonu timeit na příkazovém řádku

Můžete také použít timeit na příkazovém řádku. Zde je ekvivalent volání funkce timeit z příkazového řádku:

$ python-m timeit -n [number] -s [setup] [stmt]
  • python -m timeit představuje, že spustíme timeit jako hlavní modul.
  • n je volba příkazového řádku, která udává, kolikrát se má kód spustit. To je ekvivalentní argumentu číslo ve volání funkce timeit().
  • Pomocí volby -s můžete definovat kód nastavení.
  Jak odstranit všechny retweety na Twitteru

Zde přepíšeme předchozí příklad pomocí ekvivalentu příkazového řádku:

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

V tomto příkladu vypočítáme dobu provádění vestavěné funkce len(). Inicializace řetězce je kód nastavení, který je předán pomocí volby s.

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

Ve výstupu si všimněte, že dostáváme dobu provedení pro nejlepší z 5 běhů. Co to znamená? Když spustíte timeit na příkazovém řádku, volba opakování r je nastavena na výchozí hodnotu 5. To znamená, že provedení stmt pro zadaný počet opakování se opakuje pětkrát a vrátí se nejlepší z časů provedení.

Analýza metod obrácení řetězce pomocí timeit

Při práci s řetězci Pythonu je možná budete chtít obrátit. Dva nejběžnější přístupy k obrácení strun jsou následující:

  • Pomocí krájení provázků
  • Pomocí funkce reversed() a metody join().

Reverse Python řetězce pomocí String Slicing

Pojďme si projít, jak funguje krájení řetězců a jak jej můžete použít k obrácení řetězce Python. Pomocí syntaxe some-string[start:stop] vrátí část řetězce začínající na začátku indexu a sahající až k indexu stop-1. Vezměme si příklad.

Zvažte následující řetězec ‚Python‘. Řetězec má délku 6 a seznam indexů je 0, 1, 2 až 5.

>>> string_1 = 'Python'

Když zadáte počáteční i koncovou hodnotu, získáte řez řetězce, který sahá od začátku do konce-1. Proto řetězec_1[1:4] vrátí ‚yth‘.

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

Když nezadáte počáteční hodnotu, použije se výchozí počáteční hodnota nula a řez začíná na indexu nula a sahá až do konce – 1.

  Spin přetváří ovládání hudby na obrazovce zámku iPhone

Zde je koncová hodnota 3, takže řez začíná na indexu 0 a jde nahoru k indexu 2.

>>> string_1[:3]
'Pyt'

Když nezahrnete stop index, uvidíte, že řez začíná od počátečního indexu (1) a sahá až ke konci řetězce.

>>> string_1[1:]
'ython'

Ignorování počáteční i koncové hodnoty vrátí část celého řetězce.

>>> string_1[::]
'Python'

Vytvořme řez s hodnotou kroku. Nastavte hodnoty spuštění, zastavení a kroku na 1, 5 a 2. Získáme část řetězce začínající na 1 až po 4 (kromě koncového bodu 5) obsahující každý druhý znak.

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

Když použijete záporný krok, můžete získat řez začínající na konci řetězce. S krokem nastaveným na -2, řetězec_1[5:2:-2] dává následující plátek:

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

Abychom získali obrácenou kopii řetězce, přeskočíme počáteční a koncové hodnoty a nastavíme krok na -1, jak je znázorněno:

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

Stručně řečeno: řetězec[::-1] vrátí obrácenou kopii řetězce.

Obrácení řetězců pomocí vestavěných funkcí a metod řetězců

Vestavěná funkce reversed() v Pythonu vrátí zpětný iterátor nad prvky řetězce.

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

Takže můžete procházet reverzní iterátor pomocí smyčky for:

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

A přístup k prvkům řetězce v opačném pořadí.

# Output
n
o
h
t
y
P

Dále pak můžete zavolat metodu join() na reverzním iterátoru se syntaxí: .join(reversed(some-string)).

Níže uvedený úryvek kódu ukazuje několik příkladů, kde je oddělovačem spojovník a mezera.

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

Zde nechceme žádný oddělovač; takže nastavte oddělovač na prázdný řetězec, abyste získali obrácenou kopii řetězce:

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

Použití .join(reversed(some-string)) vrátí obrácenou kopii řetězce.

Porovnání časů provádění pomocí timeit

Dosud jsme se naučili dva přístupy k obrácení řetězců Pythonu. Ale který z nich je rychlejší? Pojďme to zjistit.

V předchozím příkladu, kde jsme časovali jednoduché výrazy Pythonu, jsme neměli žádný nastavovací kód. Zde obracíme řetězec Pythonu. Zatímco operace obrácení řetězce běží tolikrát, kolikrát je zadáno číslem, instalační kód je inicializace řetězce, který se spustí pouze jednou.

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

Pro stejný počet běhů pro obrácení daného řetězce je postup krájení řetězce rychlejší než použití metody join() a funkce reversed().

  8 varovných signálů, že váš Mac může mít problém (a jak jej opravit)

Časování funkcí Pythonu Použití timeit

V této části se naučíme, jak časovat funkce Pythonu pomocí funkce timeit. Vzhledem k seznamu řetězců vrátí následující funkce hasDigit seznam řetězců, které mají alespoň jednu číslici.

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

Nyní bychom rádi změřili dobu provádění této pythonské funkce hasDigit() pomocí timeit.

Nejprve identifikujme příkaz, který má být časován (stmt). Je to volání funkce hasDigit() se seznamem řetězců jako argumentem. Dále definujeme kód nastavení. Dokážete odhadnout, jaký by měl být kód nastavení?

Aby volání funkce proběhlo úspěšně, měl by instalační kód obsahovat následující:

  • Definice funkce hasDigit()
  • Inicializace seznamu argumentů řetězců

Pojďme definovat kód nastavení v řetězci nastavení, jak je znázorněno níže:

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ále můžeme použít funkci timeit a získat čas provedení funkce hasDigit() pro 100 000 spuštění.

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

Závěr

Naučili jste se, jak používat funkci timeit Pythonu k časování výrazů, funkcí a dalších volatelných položek. To vám může pomoci srovnat váš kód, porovnat doby provádění různých implementací stejné funkce a další.

Pojďme si zopakovat, co jsme se naučili v tomto tutoriálu. Můžete použít funkci timeit() se syntaxí timeit.timeit(stmt=…,setup=…,číslo=…). Případně můžete spustit timeit na příkazovém řádku pro načasování krátkých úryvků kódu.

Jako další krok můžete prozkoumat, jak používat další profilovací balíčky Pythonu, jako je line-profiler a memprofiler, k profilování kódu na čas a paměť.

Dále se naučte, jak vypočítat časový rozdíl v Pythonu.

x