8.2【装饰器】为被装饰的函数保持元数据

python中一切皆对象,函数也是,用def或者lambda创建时,便获得个函数对象。在函数对象中保存着一些函数的元数据,例如:
f.__name__		:函数的名字
f.__doc__		:函数文档字符串
f.__moudle__	:函数所属模块名
f.__dict__		:属性字典
f.__defaults__	:默认参数元组
...
在使用装饰器后,再使用上面这些属性访问时,看到的是内部包裹函数的元数据,原来函数的元数据便丢失了

def f(a):
	'''f function'''
	return a * 2
f.
f.__name__
g = f
g.__name__ # f ;	函数定义的时候就赋的值
f.__doc__ # ‘f function’
f.__module__ # __main__  ; 函数属于模块,当前函数不是导入的,在__main__里
f.__defaults__
def f(a,b=1,c=[]):
	print a,b,c
f.__defaults__ # (1,[]) 	;	保存函数默认参数,在python中,不是每次调用创建;而是定义函数时,直接创建好
f(100)
f.__defaults__[1].append('abc') # 100,1,['abc'] 	; 在默认参数中,尽量不要使用可变对象
f.__closure__
def f():
	a = 2
	return lambda k: a ** k
# 存在一个闭包;在f()函数退出以后,之后的lambda还可以访问a
g = f()
c = g.__closure__[0]
c.cell_contents # 2

#
def mydecorator(func):
	def wrapper(*args,	**kargs):
		'''wrapper function'''
		print 'In wrapper'
		func(*args,	**kargs)
	return wrapper

@mydecorator # 装饰后,example函数变成wrapper函数
def example():
	'''example function'''
	print 'In example'

print example.__name__ # wrapper
print example.__doc__ # wrapper function
# 但wrapper中内部数据无用,应保留example中的原数据
# 使用标准库functools中的装饰器wraps装饰内部包裹函数,可以制定将原函数的某些属性,更新到包裹函数上
from functools import update_wrapper, wraps, WRAPPER_ASSIGNMENTS, WRAPPER_UPDATES
def mydecorator(func):
	def wrapper(*args,	**kargs):
		'''wrapper function'''
		print 'In wrapper'
		func(*args,	**kargs)
	# wrapper.__name__ = func.__name__ ; 不优雅
	#update_wrapper(wrapper,func,('__name__','__doc__'),('__dict__',))
	update_wrapper(wrapper,func)
	return wrapper

@mydecorator 
def example():
	'''example function'''
	print 'In example'

print example.__name__  # example 
print example.__doc__ # example function
#print WRAPPER_ASSIGNMENTS # updata_wrapper的默认第3个参数
#print WRAPPER_UPDATES # updata_wrapper的默认第4个参数

wraps是一个函数,所以可以当装饰器直接装饰
from functools import update_wrapper, wraps, WRAPPER_ASSIGNMENTS, WRAPPER_UPDATES
def mydecorator(func):
	@wraps(func)
	def wrapper(*args,	**kargs):
		'''wrapper function'''
		print 'In wrapper'
		func(*args,	**kargs)
	return wrapper

@mydecorator 
def example():
	'''example function'''
	print 'In example'

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值