装饰器

装饰器

-----在代码运行期间动态的增加功能的方式,本质上是一个返回函数的高阶函数

功能:插入场景,性能测试,事务处理,达到代码重用的目的

函数是一个对象,可赋值给变量:

def time():
	print'2017-7-19'

f = time
f()

>>> 2017-7-19 
函数对象的 _name_函数,可以拿到函数的名字:

print time.__name__
print f.__name__

>>>time
>>>time
初步定义一个简单的装饰器:

def deco(func):
	print 'my %s():'%func.__name__

def time():
	print '2017-7-9'

deco(time)
time()

>>>my time():
>>>2017-7-9
缺点:所有的“time”调用处都要改为“deco(time)”

改进:避免装饰器deco对“time”函数的调用代码的影响,增加一个内嵌函数wrapper

ef deco(func):#装饰器接受一个函数作为参数,并返回一个函数
	def wrapper():#wrapper-->包装
		print 'my %s():'%func.__name__
		return func()
	return wrapper

def time():
	print'2017-7-9'

time = deco(time)
time()

>>>my time():
>>>2017-7-9
装饰器语法糖:用“ ”语法糖来精简装饰器的代码:

def deco(func):
	def wrapper():
		print 'my %s():'%func.__name__
		return func()
	return wrapper

@deco#相当于time = deco(time),则不需要额外代码来给“time”重新赋值
def time():
	print '2017-7-9'

time()

>>>my time():
>>>2017-7-9
两层嵌套--->被装饰的函数带参数:

def deco(func):
	def wrapper(a,b):#在内嵌函数中加上同样的参数
		print 'a + b =',a + b
		return func(a,b)
	return wrapper

@deco#相当于time = deco(time(1,2))
def time(a,b):
	print '2017-7-9'

time(1,2)

>>>my time():
>>>2017-7-9
>>>a + b = 3
>>>2017-7-9
???如果多个函数拥有不同的参数形式,怎么共用同样的装饰器:

在Python中,函数支持(*args,**kw)可变参数,所以内嵌函数可以通过可变参数来实现

三层嵌套--->带参数的装饰器:

def deco_(text):
	def deco(func):
		def wrapper(*args,**kw):
			print '%s %s():'%(text,func.__name__)
			return func(*args,**kw)
		return wrapper
	return deco

@deco_('my')#相当于deco_(’my‘)(time)
def time():
	print '2017-7-9'

time()

>>>my time():
>>>2017-7-9
程序分析:首先执行deco_('my'),返回的是deco函数,再调用返回的函数,参数是time函数,返回值最终是wrapper函数

因此,返回的名字由time变为wrapper:

def deco(func):
	def wrapper(*args,**kw):
		print '%s'%func.__name__
		return func(*args,**kw)
	return wrapper

@deco
def time():
	print time.__name__

time()

>>>time
>>>wrapper
因此,需要把原始函数的_name_等属性复制到wrapper函数中,否则,有些依赖函数签名的代码执行就会出错

因为Python中有内置的函数functools.wraps代替了wrapper._name_ = func._name_ ,则只需要在内嵌函数wrapper前面加上“@functools.wraps(func)

import functools

def deco(func):
	@functools.wraps(func)
	def wrapper(*args,**kw):
		print '%s' %func.__name__
		return func(*args,**kw)
	return wrapper

@deco
def time():
	print time.__name__

time()

>>>time
>>>time
调用顺序:与声明的顺序相反

def deco_1(func):
	print '调用deco_1'
	def wrapper(*args,**kw):
		print '调动deco_1的wrapper'
		return func(*args,**kw)
	return wrapper

def deco_2(func):
	print '调用deco_2'
	def wrapper(*args,**kw):
		print '调用deco_2的wrapper'
		return func(*args,**kw)
	return wrapper

@deco_1
@deco_2
def order():
	pass

order()#即deco_1(deco_2(order))

>>>调用deco_2
>>>调用deco_1
>>>调动deco_1的wrapper
>>>调用deco_2的wrapper


习题:

习题一:请编写一个decorator,能在函数调用的前后打印出'begin call''end call'的日志。

import functools

def deco(func):
	@functools.wraps(func)
	def wrapper(*args, **kw):
		print 'begin call %s()'%func.__name__
		func(*args, **kw)
		print 'end call %s()' % func.__name__
		#return func(*args, **kw)
	return wrapper

@deco
def diary():
	print '2017-7-9'

diary()

>>>begin call diary()
>>>2017-7-9
>>>end call diary()
习题二:能否写出一个@log的deco,使它既支持:@log                     又支持:   @log('test')

                                    def  f():                                              def  f():

                                       pass                                                  pass

def log(*text):
	def deco(func):
		@functools.wraps(func)
		def wrapper(*args, **kw):
			if len(text) == 0:
				print'log无输入参数'
			else:
				for i in text:
					print'log输入了参数:%s'%i
			return func(*args, **kw)
		return wrapper
	return deco

@log('my','deco')
@log()
def test():
	pass

test()

>>>log输入了参数:my
>>>log输入了参数:deco
>>>log无输入参数




  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值