"timeit" — 小さなコード断片の実行時間計測
*****************************************

バージョン 2.3 で追加.

**ソースコード:** Lib/timeit.py

======================================================================

このモジュールは小さい Python コードをの時間を計測するシンプルな手段を
提供しています。コマンドラインインターフェイス の他 呼び出しも可能 で
す。このモジュールは実行時間を計測するときに共通するいくつかの罠を回避
します。O’Reilly 出版の *Python Cookbook* にある、Tim Peter による 「
Algorithms」 章も参照してください。


基本的な例
==========

次の例は コマンドラインインターフェイス を使って 3 つの異なる式の時間
を測定する方法を示しています。

   $ python -m timeit '"-".join(str(n) for n in range(100))'
   10000 loops, best of 3: 40.3 usec per loop
   $ python -m timeit '"-".join([str(n) for n in range(100)])'
   10000 loops, best of 3: 33.4 usec per loop
   $ python -m timeit '"-".join(map(str, range(100)))'
   10000 loops, best of 3: 25.2 usec per loop

同じ事を Python インターフェイス を使って実現することもできます:

   >>> import timeit
   >>> timeit.timeit('"-".join(str(n) for n in range(100))', number=10000)
   0.8187260627746582
   >>> timeit.timeit('"-".join([str(n) for n in range(100)])', number=10000)
   0.7288308143615723
   >>> timeit.timeit('"-".join(map(str, range(100)))', number=10000)
   0.5858950614929199

ただし、"timeit" はコマンドラインインターフェイスを使った時だけ繰り返
し回数を自動で決定する事に注意してください。使用例 節でより高度な例を
説明しています。


Python インターフェイス
=======================

このモジュールは 3 つの有用な関数と 1 つの公開クラスを持っています:

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

   Create a "Timer" instance with the given statement, *setup* code
   and *timer* function and run its "timeit()" method with *number*
   executions.

   バージョン 2.6 で追加.

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

   Create a "Timer" instance with the given statement, *setup* code
   and *timer* function and run its "repeat()" method with the given
   *repeat* count and *number* executions.

   バージョン 2.6 で追加.

timeit.default_timer()

   Define a default timer, in a platform-specific manner.  On Windows,
   "time.clock()" has microsecond granularity, but "time.time()"』s
   granularity is 1/60th of a second.  On Unix, "time.clock()" has
   1/100th of a second granularity, and "time.time()" is much more
   precise.  On either platform, "default_timer()" measures wall clock
   time, not the CPU time.  This means that other processes running on
   the same computer may interfere with the timing.

class timeit.Timer(stmt='pass', setup='pass', timer=<timer function>)

   小さなコード片の実行時間を計測するためのクラスです。

   The constructor takes a statement to be timed, an additional
   statement used for setup, and a timer function.  Both statements
   default to "'pass'"; the timer function is platform-dependent (see
   the module doc string). *stmt* and *setup* may also contain
   multiple statements separated by ";" or newlines, as long as they
   don’t contain multi-line string literals.

   To measure the execution time of the first statement, use the
   "timeit()" method.  The "repeat()" method is a convenience to call
   "timeit()" multiple times and return a list of results.

   バージョン 2.6 で変更: The *stmt* and *setup* parameters can now
   also take objects that are callable without arguments.  This will
   embed calls to them in a timer function that will then be executed
   by "timeit()".  Note that the timing overhead is a little larger in
   this case because of the extra function calls.

   timeit(number=1000000)

      メイン文を *number* 回実行した時間を計測します。このメソッドはセ
      ットアップ文を1回だけ実行し、メイン文を指定回数実行するのにかか
      った秒数を浮動小数で返します。引数はループを何回実行するかの指定
      で、デフォルト値は 100万回です。メイン文、セットアップ文、タイマ
      ー関数はコンストラクターで指定されたものを使用します。

      注釈: デフォルトでは、"timeit()" は計測中、一時的に *ガベージ
        コレク ション* を停止します。 この手法の利点は個々の計測結果が
        より比 較しやすくなることです。 欠点は、ガベージコレクションが
        計測さ れる関数の性能の重要な要素である場合があることです。 そ
        の場合 、*setup* 文字列の最初の文でガベージコレクションを有効
        にできま す。 以下に例を示します:

           timeit.Timer('for i in xrange(10): oct(i)', 'gc.enable()').timeit()

   repeat(repeat=3, number=1000000)

      "timeit()" を複数回繰り返します。

      これは "timeit()" を繰り返し呼び出したい時に有用で、結果をリスト
      にして返します。最初の引数で何回 "timeit()" を呼ぶか指定します。
      第 2 引数で "timeit()" の引数 *number* を指定します。

      注釈: 結果のベクトルから平均値や標準偏差を計算して出力させたい
        と思う かもしれませんが、それはあまり意味がありません。多くの
        場合、最 も低い値がそのマシンが与えられたコード断片を実行する
        場合の下限 値です。結果のうち高めの値は、Python のスピードが一
        定しないた めに生じたものではなく、その他の計測精度に影響を及
        ぼすプロセス によるものです。したがって、結果のうち "min()" だ
        けが見るべき 値となるでしょう。この点を押さえた上で、統計的な
        分析よりも常識 的な判断で結果を見るようにしてください。

   print_exc(file=None)

      計測対象コードのトレースバックを出力するためのヘルパーです。

      利用例:

         t = Timer(...)       # outside the try/except
         try:
             t.timeit(...)    # or t.repeat(...)
         except:
             t.print_exc()

      The advantage over the standard traceback is that source lines
      in the compiled template will be displayed. The optional *file*
      argument directs where the traceback is sent; it defaults to
      "sys.stderr".


コマンドラインインターフェイス
==============================

コマンドラインからプログラムとして呼び出す場合は、次の書式を使います:

   python -m timeit [-n N] [-r N] [-s S] [-t] [-c] [-h] [statement ...]

以下のオプションが使用できます:

-n N, --number=N

   『statement』 を実行する回数

-r N, --repeat=N

   タイマーを繰り返す回数 (デフォルトは 3)

-s S, --setup=S

   最初に1回だけ実行する文 (デフォルトは "pass")

-t, --time

   use "time.time()" (default on all platforms but Windows)

-c, --clock

   use "time.clock()" (default on Windows)

-v, --verbose

   時間計測の結果をそのまま詳細な数値でくり返し表示する

-h, --help

   簡単な使い方を表示して終了する

文は複数行指定することもできます。その場合、各行は独立した文として引数
に指定されたものとして処理します。クォートと行頭のスペースを使って、イ
ンデントした文を使うことも可能です。この複数行のオプションは  "-s" に
おいても同じ形式で指定可能です。

オプション "-n" でループの回数が指定されていない場合、10 回から始めて
、所要時間が 0.2 秒になるまで回数を増やすことで適切なループ回数が自動
計算されるようになっています。

"default_timer()" measurations can be affected by other programs
running on the same machine, so the best thing to do when accurate
timing is necessary is to repeat the timing a few times and use the
best time.  The "-r" option is good for this; the default of 3
repetitions is probably enough in most cases.  On Unix, you can use
"time.clock()" to measure CPU time.

注釈: There is a certain baseline overhead associated with executing
  a pass statement. The code here doesn’t try to hide it, but you
  should be aware of it.  The baseline overhead can be measured by
  invoking the program without arguments, and it might differ between
  Python versions.  Also, to fairly compare older Python versions to
  Python 2.3, you may want to use Python’s "-O" option (see
  Optimizations) for the older versions to avoid timing "SET_LINENO"
  instructions.


使用例
======

最初に 1 回だけ実行されるセットアップ文を指定することが可能です:

   $ python -m timeit -s 'text = "sample string"; char = "g"'  'char in text'
   10000000 loops, best of 3: 0.0877 usec per loop
   $ python -m timeit -s 'text = "sample string"; char = "g"'  'text.find(char)'
   1000000 loops, best of 3: 0.342 usec per loop

   >>> import timeit
   >>> timeit.timeit('char in text', setup='text = "sample string"; char = "g"')
   0.41440500499993504
   >>> timeit.timeit('text.find(char)', setup='text = "sample string"; char = "g"')
   1.7246671520006203

同じことは "Timer" クラスとそのメソッドを使用して行うこともできます:

   >>> import timeit
   >>> t = timeit.Timer('char in text', setup='text = "sample string"; char = "g"')
   >>> t.timeit()
   0.3955516149999312
   >>> t.repeat()
   [0.40193588800002544, 0.3960157959998014, 0.39594301399984033]

以下の例は、複数行を含んだ式を計測する方法を示しています。ここでは、オ
ブジェクトの存在する属性と存在しない属性に対してテストするために
"hasattr()" と "try"/"except" を使用した場合のコストを比較しています:

   $ python -m timeit 'try:' '  str.__nonzero__' 'except AttributeError:' '  pass'
   100000 loops, best of 3: 15.7 usec per loop
   $ python -m timeit 'if hasattr(str, "__nonzero__"): pass'
   100000 loops, best of 3: 4.26 usec per loop

   $ python -m timeit 'try:' '  int.__nonzero__' 'except AttributeError:' '  pass'
   1000000 loops, best of 3: 1.43 usec per loop
   $ python -m timeit 'if hasattr(int, "__nonzero__"): pass'
   100000 loops, best of 3: 2.23 usec per loop

   >>> import timeit
   >>> # attribute is missing
   >>> s = """\
   ... try:
   ...     str.__nonzero__
   ... except AttributeError:
   ...     pass
   ... """
   >>> timeit.timeit(stmt=s, number=100000)
   0.9138244460009446
   >>> s = "if hasattr(str, '__bool__'): pass"
   >>> timeit.timeit(stmt=s, number=100000)
   0.5829014980008651
   >>>
   >>> # attribute is present
   >>> s = """\
   ... try:
   ...     int.__nonzero__
   ... except AttributeError:
   ...     pass
   ... """
   >>> timeit.timeit(stmt=s, number=100000)
   0.04215312199994514
   >>> s = "if hasattr(int, '__bool__'): pass"
   >>> timeit.timeit(stmt=s, number=100000)
   0.08588060699912603

定義した関数に "timeit" モジュールがアクセスできるようにするために、
import 文の入った *setup* パラメーターを渡すことができます:

   def test():
       """Stupid test function"""
       L = []
       for i in range(100):
           L.append(i)

   if __name__ == '__main__':
       import timeit
       print(timeit.timeit("test()", setup="from __main__ import test"))
