装饰器的原则
1)不修改被修饰函数的源代码;
2)不修改被修饰函数的调用方式;
装饰器的知识点 = 高阶函数 + 函数嵌套 + 闭包
1. 只用高阶函数写装饰器--->有瑕疵
import time def foo(): print('this is foo') # return foo def timer(func): starttime = time.time() func() stoptime = time.time() print('使用的时间是:%s' %(stoptime - starttime)) return func foo = timer(foo) foo() #执行结果是: # this is foo # 使用的时间是:0.00013685226440429688 # this is foo #多了一次执行结果
2. 闭包其实就是函数的嵌套
def First(name): print('FirstLayer:%s' %name) def Second(): name = 'bbb' print('SecondLayer:%s' %name) def Third(): name = 'ccc' print('ThirdLayer:%s' %name) Third() Second() First('aaa')
3. 函数闭包装饰器基本实现
# 实现阶段1:只需要在原来函数调用之前进行赋值操作。 import time def timer(func): #func == test def good(): starttime = time.time() func() stoptime = time.time() print('程序消耗的时间是:%s' %(stoptime - starttime)) return good def test(): print('这是test函数') test = timer(test) #此处函数运行的结果是return的good,可以看下一步证实。 print(timer(test)) #<function timer.<locals>.good at 0x10e3cb700>,因此需要下一步运行返回值函数good。 test() #test = good
# 实现阶段2:通过语法糖改进后,完全不需要动原来函数; import time def timer(func): #func == test def good(): starttime = time.time() func() stoptime = time.time() print('程序消耗的时间是:%s' %(stoptime - starttime)) return good @timer #@timer 相当于 test = timer(test) def test(): print('这是test函数') test()
# 实现阶段3:如何打印出真正test的返回值 import time def timer(func): #func == test def good(): starttime = time.time() res = func() #就是在运行test() stoptime = time.time() print('程序消耗的时间是:%s' %(stoptime - starttime)) return res return good @timer #@timer 相当于 test = timer(test) def test(): print('这是test函数') return '这是test的返回值' ras = test() print(ras)
# 阶段4装饰器适用于不同参数个数的函数 import time def timer(func): #func == test def good(*args,**kwargs): starttime = time.time() res = func(*args,**kwargs) #就是在运行test() stoptime = time.time() print('程序消耗的时间是:%s' %(stoptime - starttime)) return res return good @timer #@timer 相当于 test = timer(test) def test(name,age,gender): print('这是test函数,名字是%s,年龄是%s,性别是%s' %(name,age,gender)) return '这是test的返回值' ras = test('aaa','18','male') print(ras) @timer #@timer 相当于 test1 = timer(test1) def test1(name,age,gender,hight): print('这是test1函数,,名字是%s,年龄是%s,性别是%s,身高是%s' %(name,age,gender,hight)) return '这是test1的返回值' ras = test1('bbb','20','male','175') print(ras) # 如下为返回结果: # 这是test函数,名字是aaa,年龄是18,性别是male # 程序消耗的时间是:8.0108642578125e-05 # 这是test的返回值 # 这是test1函数,,名字是bbb,年龄是20,性别是male,身高是175 # 程序消耗的时间是:1.0013580322265625e-05 # 这是test1的返回值
4. 解压序列补充
# 使用解压序列取列表中的最开头和最结尾的值,可灵活使用。 >>> l = [1,2,3,4,5,6] >>> a,*_,b = l >>> l [1, 2, 3, 4, 5, 6] >>> a 1 >>> b 6 >>> a,*b,c = l >>> a 1 >>> b [2, 3, 4, 5] >>> c 6
#快速交换两个变量的值 >>> f1,f2 = 1,2 >>> f1 1 >>> f2 2 >>> f1,f2 = f2,f1 >>> f1 2 >>> f2 1
5. 终极版装饰器-带参数验证功能的装饰器
user_list=[ {'name':'alex','passwd':'123'}, {'name':'linhaifeng','passwd':'123'}, {'name':'wupeiqi','passwd':'123'}, {'name':'yuanhao','passwd':'123'}, ] current_dic={'username':None,'login':False} def auth(auth_type='filedb'): def auth_func(func): def wrapper(*args,**kwargs): print('认证类型是',auth_type) if auth_type == 'filedb': if current_dic['username'] and current_dic['login']: res = func(*args, **kwargs) return res username=input('用户名:').strip() passwd=input('密码:').strip() for user_dic in user_list: if username == user_dic['name'] and passwd == user_dic['passwd']: current_dic['username']=username current_dic['login']=True res = func(*args, **kwargs) return res else: print('用户名或者密码错误') elif auth_type == 'ldap': print('鬼才特么会玩') res = func(*args, **kwargs) return res else: print('鬼才知道你用的什么认证方式') res = func(*args, **kwargs) return res return wrapper return auth_func @auth(auth_type='filedb') #auth_func=auth(auth_type='filedb')-->@auth_func 附加了一个auth_type --->index=auth_func(index) def index(): print('欢迎来到京东主页') @auth(auth_type='ldap') def home(name): print('欢迎回家%s' %name) # @auth(auth_type='sssssss') def shopping_car(name): print('%s的购物车里有[%s,%s,%s]' %(name,'奶茶','妹妹','娃娃')) # print('before-->',current_dic) # index() # print('after--->',current_dic) # home('产品经理') shopping_car('产品经理')