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)は何かって? それが分からんのだよ。 省略すると、複数の関数をデコレーションした時におかしくなるんだけどね。後はよく分からん。