Python でプログラムのパフォーマンスを向上させるためには、コードの実行時間を計測し、ボトルネックを見つけることが重要です。timeit
モジュールは、この目的のために設計された標準ライブラリで、簡単かつ正確にコードの実行時間を測定することができます。本記事では、timeit
モジュールの使用方法や、実用的な活用例について詳しく解説します。
1. timeit
モジュールの概要
timeit
は、Python コードの実行時間を高精度で計測するためのモジュールです。特に、以下の特徴があります:
- 簡単にコードのパフォーマンスを測定:わずかなコードで実行時間を計測可能。
- ノイズを排除:計測中にガベージコレクションを一時停止することで、より正確な時間を測定。
- 柔軟な使用方法:コマンドラインインターフェース(CLI)とスクリプト実行の両方をサポート。
2. timeit
の基本的な使い方
コマンドラインインターフェースでの使用
コマンドラインから timeit
を実行する場合、シンプルなワンライナーや短いコードを計測するのに適しています。
python -m timeit [-n N] [-r N] [-s S] [statement]
主なオプション
-n N
:コードを実行する回数を指定します。-r N
:計測を繰り返す回数(デフォルトは 5 回)。-s S
:実行前に 1 度だけ実行されるセットアップコード。
使用例
$ python -m timeit -s 'text = "hello world"' '"world" in text'
10000000 loops, best of 5: 0.045 sec per loop
一方、スクリプト内で timeit
を使用する場合は、より柔軟な計測が可能です。
スクリプト内での使用
スクリプト内で timeit
を使用する場合は、以下の関数が利用可能です:
timeit.timeit
:指定したコードを一定回数実行し、実行時間を計測。timeit.repeat
:計測を複数回繰り返し、リスト形式で結果を返します。
基本的な使用例
import timeit
# 単純なコードの実行時間を計測
print(timeit.timeit('"-".join(str(n) for n in range(100))', number=10000))
# 繰り返し回数を指定して複数回計測
print(timeit.repeat('"-".join(str(n) for n in range(100))', number=10000, repeat=5))
3. Timer クラスを使用した計測
Timer
クラスを使用すると、セットアップコードを柔軟に指定できます。
使用例
from timeit import Timer
setup_code = 'numbers = list(range(1000))'
test_code = 'sum(numbers)'
t = Timer(stmt=test_code, setup=setup_code)
print(t.timeit(number=10000))
ここでは、リストの合計を計算するコードの実行時間を測定しています。
複数行コードの計測
複数行にわたるコードも timeit
で計測できます。
code = '''
for i in range(100):
x = i ** 2
'''
print(timeit.timeit(stmt=code, number=1000))
4. よくあるエラーと対処法
NameError の対処
timeit
モジュールでは、デフォルトでコードをグローバル名前空間内で実行します。そのため、ローカル名前空間で定義された関数や変数を認識できず、NameError
が発生することがあります。この仕様により、計測対象のコードはグローバルスコープにある必要があります。
エラー例
def example_function():
return sum(range(100))
import timeit
# これではエラーになる
print(timeit.timeit('example_function()'))
上記のコードでは、example_function
がローカル名前空間に定義されているため、timeit
がその名前を認識できず NameError
が発生します。
修正版
この問題を解決するには、globals
引数を指定して、timeit
に現在のグローバル名前空間を渡します。
def example_function():
return sum(range(100))
import timeit
# globals を指定して関数を認識させる
print(timeit.timeit('example_function()', globals=globals()))
このように、globals
を使用することで、timeit
がグローバルスコープ内の関数や変数を正しく認識できるようになります。
5. ガベージコレクションと timeit
timeit
は、デフォルトで計測中にガベージコレクションを無効化します。この挙動は計測結果にノイズを含ませないためですが、ガベージコレクションが重要な場合は有効にする必要があります。
ガベージコレクションを有効化
import timeit
gc_enabled_code = 'for i in range(100): oct(i)'
setup_code = 'import gc; gc.enable()'
print(timeit.timeit(gc_enabled_code, setup=setup_code, number=10000))
6. 実用例:コードの最適化
timeit
を使用すると、異なるコード実装のパフォーマンスを比較できます。
リスト内包表記 vs. for ループ
list_comp = '[i**2 for i in range(1000)]'
for_loop = '''
result = []
for i in range(1000):
result.append(i**2)
'''
print("List Comprehension:", timeit.timeit(list_comp, number=10000))
print("For Loop:", timeit.timeit(for_loop, number=10000))
結論
timeit
モジュールは、Python プログラムのパフォーマンスを向上させるために非常に役立つツールです。コードの実行時間を正確に測定することで、効率的なアルゴリズムや実装方法を見つけることができます。ぜひ、日常のコーディングやプロジェクトで活用してみてください!