hakeの日記

Windows環境でプログラミングの勉強をしています。

python - 関数デコレータ

デコレート対象関数の実行前後に処理を追加する。


使用方法は、対象関数の定義の上の@デコレータ名を追加する。

@deco
def myfunc(x):

とすることで、myfuncをdecoの引数にするイメージ?

def deko(myfunc)
	def wrapper(x):
		do_something
	return wrapper

使用例

myfuncは引数に負数を渡されるとValuErrorになる。
デコレータdeco_test1はmyfunc実行前に引数を確認して負数の場合はゼロに置き換える。

# coding: cp932

def deco_test1(f):   # f はデコレート対象の関数
	""""
	関数デコレータ
	デコレート対象の関数の引数が負数の場合は
	ゼロを引数として関数に渡す
	"""
	def wrapper(x):    # x はfの引数
		if x < 0:
			v = 0
		else:
			v = x
		r = f(v)
		return r

	return wrapper


@deco_test1
def myfunc(x):
	"""
	xが負数の場合はエラー
	その他の場合は、x*x
	"""
	if x < 0:
		raise ValueError("値が負数です")
	return x * x


print(myfunc(2))     # -> 4
print(myfunc(-1))    # -> 0 デコレートしていない場合はValueError

デコレータが引数を持つ場合

デコレータが引数を持つようになったので、wrapper関数の外側に、デコレート対象関数を引数とするdecorate関数を追加する。


デコレータdeco_test2は引数maxを持ち、myfunc実行結果がmaxより大きい場合はmaxに置き換える。

# coding: cp932

def deco_test2(max):   # max はデコレータの引数
	""""
	関数デコレータ
	デコレート対象の関数の引数が負数の場合は
	ゼロを引数として関数に渡す
	関数の戻り値が関数デコレータの引数より大きい場合は引数に置き換える
	"""
	def decorator(f):      # f はデコレート対象の関数
		def wrapper(x):    # x はfの引数
			if x < 0:
				v = 0
			else:
				v = x
			r = f(v)
			
			if r > max: r = max
			return r

		return wrapper
	return decorator


@deco_test2(50)  # 戻り値のmaxを50とする
def myfunc(x):
	"""
	xが負数の場合はエラー
	その他の場合は、x*x
	"""
	if x < 0:
		raise ValueError("値が負数です")
	return x * x


print(myfunc(2))     # -> 4
print(myfunc(-1))    # -> 0 デコレートしていない場合はValueError
print(myfunc(7))     # -> 49
print(myfunc(8))     # -> 50 デコレートしていない場合は64