timeitモジュールのtimeit関数は小規模なコードの実行時間を計測するのに使える。その基本的な使い方を紹介する。
この記事は会員限定です。会員登録(無料)すると全てご覧いただけます。
# 基本型
import timeit
# 実行するPythonコード(文)を文字列として用意しておく
bycomp = '"".join([chr(c) for c in range(ord("a"), ord("a")+26)])'
bymap = '"".join(map(chr, range(ord("a"), ord("a")+26)))'
# Pythonの文を文字列として渡す
t = timeit.timeit(bycomp)
print(t) # 1.6198786449967884など
t = timeit.timeit(bymap)
print(t) # 1.2530384509882424など
# セットアップで実行する文(第1引数)の準備をする
from math import sqrt
t = timeit.timeit('sqrt(2)') # NameError:timeitの名前空間ではsqrtが未定義
t = timeit.timeit('sqrt(2)', 'from math import sqrt')
t = timeit.timeit('a + b', 'a = 10; b = 20')
# setupで関数を定義して、stmtでその関数を呼び出す
deffunc = '''
def myfunc():
return "".join(map(chr, range(ord("a"), ord("a")+26)))
'''
callfunc = 'myfunc()'
t = timeit.timeit(callfunc, deffunc)
# 名前空間を指定する
def foo():
return "".join(map(chr, range(ord("a"), ord("a")+26)))
timeit.timeit('foo()') # NameError:timeitモジュール内で未定義のため
timeit.timeit('foo()', globals=globals()) # 現在のグローバル名前空間を渡す
# 呼び出し可能オブジェクト(引数なし)を渡す
timeit.timeit(foo)
# 実行回数を指定する
t = timeit.timeit(bymap, number=100000)
# タイマーの種類を変更する
import time
t = timeit.timeit(bymap, timer=time.process_time)
# timeit.timeit関数を複数回呼び出す
t = timeit.repeat('"".join([chr(c) for c in range(ord("a"), ord("a")+26)])')
print(t)
# 出力結果
# [1.572056960008922, 1.5784977519942913, 1.5998643350030761, 1.5844960929971421, 1.5959375229867874]
Pythonに標準で添付のtimeitモジュールは規模の小さなコードの実行時間を計測するのに役立つ。コマンドラインツールとしても使えるが、本稿ではPythonコードとしてこのモジュールを使って実行時間を計測する方法を紹介する。
timeitモジュールが提供するtimeit関数の構文を以下に示す。
timeit.timeit(stmt='pass', setup='pass', timer=<default timer>, number=1000000, globals=None)
パラメーターの意味は以下の通りだ。
例えば、'a'から'z'の各文字を連結するには幾つかの方法があるだろう。そこで、ここではリスト内包表記を使う方法とmap関数を使う方法の実行時間を計測したいとする。それらのコードをまず文字列として用意しておく。
bycomp = '"".join([chr(c) for c in range(ord("a"), ord("a")+26)])'
bymap = '"".join(map(chr, range(ord("a"), ord("a")+26)))'
文字列としたPythonコードをtimeit.timeit関数に渡せば、それをnumber回だけ実行し、それにかかった時間が返される。
t = timeit.timeit(bycomp)
print(t) # 1.6198786449967884など
t = timeit.timeit(bymap)
print(t) # 1.2530384509882424など
この結果からはmap関数を使った方が速そうなことが分かる。
このように、ちょっとしたコードの実行時間を手軽に計測するのにtimeit.timeit関数は便利に使える。
その一方で注意すべき点も幾つかある。まず、stmtやsetupに引き渡されたコードは特に指定をしない限り、timeitモジュールの名前空間内で実行されることだ。
例えば、mathモジュールのsqrt関数の実行時間を計測したいとする。このときに以下のようなコードを書いてもNameError例外が発生する。
from math import sqrt
t = timeit.timeit('sqrt(2)') # NameError:timeitの名前空間ではsqrtが未定義
「from math import sqrt」として現在の名前空間にsqrt関数をインポートしても、デフォルトではtimeitモジュールの名前空間でコードが実行されるので、意味がないのだ。
sqrt関数を実行できるようにするには、setupでtimeitモジュールの名前空間にsqrt関数をインポートすることが考えられる。これを行っているのが以下だ。
t = timeit.timeit('sqrt(2)', 'from math import sqrt')
このように、stmtには実行時間を計測したいコードを、setupにはそのために必要な準備(セットアップ)を行うコードを記述する。setupに書いたコードは実行時間の計測対象とはならない。
Copyright© Digital Advantage Corp. All Rights Reserved.