装饰器

装饰器

装饰器(无参)
	它是一个函数
	函数作为它的实参。无参装饰器实际上就是一个单形参函数
	返回值也是一个函数
	可以使用@functionname方式,简化调用
	注:此处装饰器的定义只是就目前所学的总结,并不准确,只是方便理解
装饰器和高阶函数
	装饰器可以是高阶函数,但装饰器是对传入函数的功能的装饰(功能增强)
装饰器例:
		import datetime
		import time
		def logger(fn):
			def wrapper(*args, **kwargs):  ##括号里面为形参
				# before 功能增强
				print("args={}, kwargs={}".format(args,kwargs))
				start = datetime.datetime.now() # 计算时长
				ret = fn(*args, **kwargs)   ##括号里面为参数解构
				# after 功能增强
				duration = datetime.datetime.now() - start
				print("function {} took {}s.".format(fn.__name__, duration.total_seconds()))
				return ret
			return wrapper
		 @logger
		def add(x, y):
			print("===call add===========")
			time.sleep(2)
			return x + y
		print(add(4, y=7))
	 @logger 是什么?这就是装饰器语法,相当于 add = logger(add) 也就相当于 = wrapper, add()就是wrapper(),调用wrappe返回fn()的返回值,而fn是调用logger(fn)的fn,用到了闭包,所以wrappe()的返回值还是add()的返回值

装饰器副作用:

		def logger(fn):
			def wrapper(*args,**kwargs):
				'I am wrapper'
				print('begin')
				x = fn(*args,**kwargs)
				print('end')
				return x
			return wrapper
	
		@logger    #add = logger(add)
		def add(x,y):
			'''This is a function for add'''
			return x + y
		print("name={}, doc={}".format(add.__name__, add.__doc__))
        如上例,用logger装饰器装饰add,实际上add = logger(add) = wrapper,所以此时add.__name__是 wrapper__name__,使用装饰器,原函数对象的属性都被替换了,我们的需求是查看原函数的属性,如何解决?  

 提供一个函数,被封装函数属性 copy> 包装函数属性

		def copy_properties(src, dst): # 可以改造成装饰器
			dst.__name__ = src.__name__
			dst.__doc__ = src.__doc__
			
		def logger(fn):
			def wrapper(*args,**kwargs):
				'I am wrapper'
				print('begin')
				x = fn(*args,**kwargs)
				print('end')
				return x
				copy_properties(fn, wrapper)
			return wrapper
			
		@logger   #add = logger(add)
		def add(x,y):
			'''This is a function for add'''
			return x + y
		print("name={}, doc={}".format(add.__name__, add.__doc__))
> 通过copy_properties函数将被包装函数的属性覆盖掉包装函数
> 凡是被装饰的函数都需要复制这些属性,这个函数很通用
> 可以将复制属性的函数构建成装饰器函数,带参装饰器

 提供一个函数,被封装函数属性 copy> 包装函数属性,改造成带参装饰器

	def copy_properties(src): # 柯里化
		def _copy(dst):
			dst.__name__ = src.__name__
			dst.__doc__ = src.__doc__
			return dst
		return _copy
	def logger(fn):
		@copy_properties(fn)    # copy_properties(fn)=_copy,wrapper=@copy_properties(fn)   (wrapper)=@_copy(wrapper)=wrapper----属于带参装饰器
		def wrapper(*args,**kwargs):
			'I am wrapper'
			print('begin')
			x = fn(*args,**kwargs)
			print('end')
			return x
		return wrapper
		
	@logger #add = logger(add)
	def add(x,y):
	'''This is a function for add'''
	return x + y
	print("name={}, doc={}".format(add.__name__, add.__doc__))

 需求:获取函数的执行时长,对时长超过阈值的函数记录一下

	def logger(duration):
		def _logger(fn):
			@copy_properties(fn) # wrapper = wrapper(fn)(wrapper)
			def wrapper(*args,**kwargs):
				start = datetime.datetime.now()
				ret = fn(*args,**kwargs)
				delta = (datetime.datetime.now() - start).total_seconds()
				print('so slow') if delta > duration else print('so fast')
				return ret
			return wrapper
		return _logger
	@logger(5) #   add = logger(5)(add)=_logger(add)=wrapper-----属于带参装饰器
	def add(x,y):
		time.sleep(3)
		return x + y
	print(add(5, 6))

带参装饰器

	> 它是一个函数
	> 函数作为它的形参
	> 返回值是一个不带参的装饰器函数
	> 使用@functionname(参数列表)方式调用
	> 可以看做在装饰器外层又加了一层函数,这个函数可以多参数
	> 将记录的功能提取出来,这样就可以通过外部提供的函数来灵活的控制输出  
	def logger(duration, func=lambda name, delta: print('{} took {:.2f}s'.format(name, delta))):-----提供多参
		def _logger(fn):
			@copy_properties(fn) # wrapper = wrapper(fn)(wrapper)
			def wrapper(*args,**kwargs):
				start = datetime.datetime.now()
				ret = fn(*args,**kwargs)
				delta = (datetime.datetime.now() - start).total_seconds()
				if delta > duration:
				func(fn.__name__, delta)
				return ret
			return wrapper
		return _logger
使用形式@logger(duration, func=lambda name, delta: print('{} took {:.2f}s'.format(name, delta)))
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值