Blanktar

  1. top
  2. blog
  3. 2013
  4. 04

pythonのデコレータを使ってお手軽ベンチマーク

pythonにはデコレータというよく分からないものがありまして。 よく分からないので込み入った解説はしないけれど、ともかく関数をデコレーションするもののようです。

使い方は簡単 ・・・かは分からないけれど、まあそれなりに。

import time
import functools

def Timer(func):
    @functools.wraps(func)
    def Wrapper(*args, **kw):
        stime = time.clock()
        ret = func(*args, **kw)
        etime = time.clock()
        print '{0}: {1:,f}ms'.format(func.__name__, (etime-stime)*1000)
        return ret
    return Wrapper

@Timer
def Test():
    print 'hello, decorator'

Test()

こんな感じで使うと、Test関数の実行時間を測ってくれます。計測対象はいくつでもおっけー。

計りたい関数の上に一行付け足すだけだから、お手軽でいいよね。 ミリ秒単位で測ってる割に関数のオーバーヘッドを考慮してないから、あんまよろしくないですが。

デコレーターに引数を付けたい時は

import time
import functools

def Timer(name):
    def Deco(func):
        @functools.wraps(func)
        def Wrapper(*args, **kw):
            stime = time.clock()
            ret = func(*args, **kw)
            etime = time.clock()
            print '{0}: {1:,f}ms'.format(name, (etime-stime)*1000)
            return ret
        return Wrapper
    return Deco

@Timer('decorator test')
def Test():
    print 'hello, decorator'

Test()

なんてやればおっけー。 三重のdefとかあんまり使いたくないけどね・・・見づらい・・・。

ちなみに、内部的には

def Deco(func):
    def Wrapper(*args, **kw):
        print func.__name__
        return func(*args, **kw)
    return Wrapper

def Test():
    print 'a'

Test = Deco(Test)

ってやるのと同義みたいね。

引数付きの場合は

Test = Deco(u'引数')(Test)

ということになるみたい。

じゃあ@functools.wraps(func)は何かって? それが分からんのだよ。 省略すると、複数の関数をデコレーションした時におかしくなるんだけどね。後はよく分からん。