装饰器本质:就是函数,功能是为其他函数添加附加功能

装饰器原则:

不修改被修饰函数的源代码 不修改修饰函数的调用方式

装饰器的知识储备:

装饰器 = 高阶函数 + 函数嵌套 + 闭包

初识装饰器

先看一个需求:下面这个函数用来计算1到20的和

def calc(l): res = 0 for i in l: time.sleep(0.01) res += i return resresult = calc(range(1,21))print(result)

但现在需求有变,不仅要计算1到20的和,还需要计算该函数运行的时间,此时装饰器就应需而生

import timedef timer(func): def wrapper(*args,**kwargs): start_time = time.time() res = func(*args,**kwargs) stop_time = time.time() print('函数运行的时间为:%s' % (stop_time - start_time)) return res return wrapper@timerdef calc(l): res = 0 for i in l: time.sleep(0.01) res += i return resresult = calc(range(1,21))print(result)

运行结果如下:

函数运行的时间为:0.2048475742340088210

上面的timer函数就是calc函数的装饰器

高阶函数

高阶函数定义:
1.函数接收的参数是一个函数名

2.函数的返回值是一个函数名

3.满足上述条件任意一个,都可称之为高阶函数

高阶函数示例

def foo(): print('我的函数名作为参数传给高阶函数')def gao_jie1(func): print('我就是高阶函数1,我接收的参数名是%s' %func) func()def gao_jie2(func): print('我就是高阶函数2,我的返回值是%s' %func) return funcgao_jie1(foo)gao_jie2(foo)把函数当作参数传给高阶函数

#高阶函数应用1:把函数当做参数传给高阶函数import timedef foo(): print('from the foo')def timmer(func): start_time=time.time() func() stop_time=time.time() print('函数%s 运行时间是%s' %(func,stop_time-start_time))timmer(foo)#总结:我们确实为函数foo增加了foo运行时间的功能,但是foo原来的执行方式是foo(),现在我们需要调用高阶函数timmer(foo),改变了函数的调用方式函数返回值是函数名

#高阶函数应用2:把函数名当做参数传给高阶函数,高阶函数直接返回函数名import timedef foo(): print('from the foo')def timmer(func): start_time=time.time() return func stop_time=time.time() print('函数%s 运行时间是%s' %(func,stop_time-start_time))foo=timmer(foo)foo()#总结:我们确实没有改变foo的调用方式,但是我们也没有为foo增加任何新功能

高阶函数总结
1.函数接收的参数是一个函数名
  作用:在不修改函数源代码的前提下,为函数添加新功能,
  不足:会改变函数的调用方式
2.函数的返回值是一个函数名
  作用:不修改函数的调用方式
  不足:不能添加新功能

函数嵌套

def father(name): print('from father %s' %name) def son(): print('from son') def grandson(): print('from grandson') grandson() son()father('Poe')闭包

'''闭包:在一个作用哉里放放定义变量,相当于打了一个包'''def father(name): def son(): print('My father is %s' %name) def grandson(): print('my grandpa is %s' %name) grandson() son()father('Poe')无参数装饰器

无参装饰器=高级函数+函数嵌套

基本框架

'''这就是一个实现 装饰器最基本的架子'''def timer(func): def wrapper(): func() return wrapper()

回到上面需要计算函数运行时间的需求,在不使用装饰器的情况下加上以下代码

import timedef timer(func): def wrapper(): startTime = time.time() func() stopTime = time.time() print('函数运行时间为:%s' % (stopTime - startTime)) return wrapperdef test(): time.sleep(3) print('test函数运行完毕')res = timer(test)res()

使用装饰器

import timedef timer(func): def wrapper(): startTime = time.time() func() stopTime = time.time() print('函数运行时间为:%s' % (stopTime - startTime)) return wrapper@timer #相当于test = timer(test)def test(): time.sleep(3) print('test函数运行完毕')test()

返回值问题
如果test函数中有返回值怎么返回呢?test函数被调用时,实质就是调用wrapper函数,如果要返回test函数中的值,必须要在wrapper函数中将该值返回

import timedef timer(func): def wrapper(): startTime = time.time() res = func() stopTime = time.time() print('该函数运行时间为:%s' % (stopTime - startTime)) return res return wrapper@timerdef test(): time.sleep(1) print('该函数运行完毕') return '这是test的返回值'res = test() #实质调用的是wrapper函数print(res)带参数的装饰器

import timedef timer(func): def wrapper(*args,**kwargs): startTime = time.time() res = func(*args,**kwargs) stopTime = time.time() print('该函数运行时间为:%s' % (stopTime - startTime)) return res return wrapper@timer #test = timer(test)def test(name,age): time.sleep(1) print('该函数运行完毕,name is %s,age is %s' %(name,age)) return '这是test的返回值'res = test('andy',18) #实质调用的是wrapper函数print(res)补充知识:解压序列

>>> a,b,c=(2,3,4)>>> a2>>> b3>>> c4

a , b, c变量要与元组中的元素一一对应才能取到值
那么再看一个实例:

>>> l=[1,2,3,4,5,6,7,8]

利用序列的方法如何取得上面列表中的第一个元素与最后一个元素

>>> l=[1,2,3,4,5,6,7,8]>>> l[1, 2, 3, 4, 5, 6, 7, 8]>>> a,*_,c=l>>> a1>>> c8>>> a,*b,c=l>>> a1>>> b[2, 3, 4, 5, 6, 7]>>> c8

注意:号代表除a,c变量外所有元素,号后面必须要有一个变量,使用下划线表示*号代表的变量不想被取出

该方法可用来交换两个变量的值:

>>> a=1>>> b=2>>> a,b=(b,a)>>> a2>>> b1装饰器示例

user_list = [ {'name':'andy','passwd':'123'}, {'name':'bruce','passwd':'123'}, {'name':'poe','passwd':'123'}, {'name':'jacky','passwd':'123'},]current_dic = {'username':None,'login':False}def auth_func(func): def wrapper(*args,**kwargs): if current_dic['username'] and current_dic['login']: res = func(*args,**kwargs) return res username = input('username:').strip() password = input('password:').strip() for user_dic in user_list: if username == user_dic['name'] and password == user_dic['passwd']: current_dic['username'] = username current_dic['login'] = True res = func(*args,**kwargs) return res else: print('用户名或密码错误') return wrapper@auth_funcdef index(): print('欢迎来到JD主页' )@auth_funcdef home(name): print('welcome %s to home' % name)@auth_funcdef shopping(name): print('%s的购物车里有%s,%s,%s' %(name,'奶茶','妹妹','牙膏'))print('before : ',current_dic)index()home('andy')shopping('andy')print('after: ',current_dic)

代码执行结果:

before : {'username': None, 'login': False}username:andypassword:123欢迎来到JD主页welcome andy to homeandy的购物车里有奶茶,妹妹,牙膏after: {'username': 'andy', 'login': True}