[解決!Python]timeitモジュールで実行時間を計測するには解決!Python

timeitモジュールのtimeit関数は小規模なコードの実行時間を計測するのに使える。その基本的な使い方を紹介する。

» 2023年07月25日 05時00分 公開
[かわさきしんじDeep Insider編集部]

この記事は会員限定です。会員登録(無料)すると全てご覧いただけます。

「解決!Python」のインデックス

連載目次

# 基本型
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]


timeitモジュール

 Pythonに標準で添付のtimeitモジュールは規模の小さなコードの実行時間を計測するのに役立つ。コマンドラインツールとしても使えるが、本稿ではPythonコードとしてこのモジュールを使って実行時間を計測する方法を紹介する。

 timeitモジュールが提供するtimeit関数の構文を以下に示す。

timeit.timeit(stmt='pass', setup='pass', timer=<default timer>, number=1000000, globals=None)


 パラメーターの意味は以下の通りだ。

  • stmt:実行時間を計測したいPythonコード(文)
  • setup:stmtを実行できるようにするための準備(文)
  • timer:実行時間の計測に使用するタイマーの指定
  • number:stmtを実行する回数
  • globals:stmtを実行する名前空間の指定

 例えば、'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.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。