一 什么是装饰器呢?
装饰器本质上来说就是函数,功能就是为其它函数添加附加功能。
原则:
- 不修改被修饰函数的源代码
- 不修改被修饰函数的调用方式
组织结构:
装饰器=高阶函数+函数嵌套+闭包
实例1(Python3.0+):
# 使用高阶函数试图完成装饰器
import time
# 定义函数foo
def foo():
time.sleep(3)
print('你好啊,林师傅')
# 定义函数test来装饰foo函数,计算foo函数的运行时间
def test(func):
start_time = time.time()
print(func)
func()
stop_time=time.time()
print('函数的运行时间:%s' %(stop_time-start_time))
test(foo)
# 改变了被修饰函数(foo())的调用方式,不满足装饰器的特性,所以不是合格的装饰器
实例2(Python3.0+):
简单装饰器的创建思路
import time
# 先架设装饰器的架子:高阶函数+函数嵌套+闭包
def timer(func): # func=test
def wrapper():
start_time=time.time()
# print(func)
func() # 就是在运行test()
stop_time=time.time()
print('函数的运行时间:%s' %(stop_time-start_time))
return wrapper
def test():
time.sleep(2)
print('函数运行结果')
# test返回的就是wrapper
test=timer(test)
# 执行test()就相当于执行wrapper()
test()
'''
以上例子实现了装饰器的部分功能:
1、没有改变原有函数的源代码,但是改变了函数的调用方式
'''
# 思考:怎么才能不改变被修饰函数的调用方式呢,我们可以采用语法糖的方式。
# 语法糖 @
# @timer 就相当于test=timer(test)
import time
# 架设装饰器的架子:高阶函数+函数嵌套+闭包
def timer(func): # func=test
def wrapper():
start_time=time.time()
# print(func)
func() # 就是在运行test()
stop_time=time.time()
print('函数的运行时间:%s' %(stop_time-start_time))
return wrapper
@timer
def test():
time.sleep(2)
print('函数运行结果')
test()
# 如果我想打印被修饰函数的返回值呢?:
# 实例1:
#
import time
# 装饰器的架子:高阶函数+函数嵌套+闭包
def timer(func): # func=test
def wrapper():
start_time=time.time()
# print(func)
func() # 就是在运行test()
stop_time=time.time()
print('函数的运行时间:%s' %(stop_time-start_time))
return wrapper
@timer # test = timer(test)
def test():
time.sleep(2)
print('函数运行结束')
return '这是test的返回值'
res=test()
# test()实际上运行的是wrapper() 原因:1.@timer 等于 test=timer(test) ,所以实际上运行test()相当于timer()(),也就是test=wrapper
print(res)
# 实际上打印的是wrapper的返回值,但wrapper函数没有ruturn返回值,所以得到的结果为None
'''
函数运行结束
函数的运行时间:2.0001144409179688
None
'''
# 实例1中没有实现打印被修饰函数返回值的功能,看看以下代码呢;
# 实例2:
#
import time
# 装饰器的架子:高阶函数+函数嵌套+闭包
def timer(func): # func=test
def wrapper():
start_time=time.time()
res=func()
# print(func)
# func() # 就是在运行test()
stop_time=time.time()
print('函数的运行时间:%s' %(stop_time-start_time))
return res
return wrapper
@timer # test = timer(test)
def test():
time.sleep(2)
print('函数运行结束')
return '这是test的返回值'
print(test())
'''
打印结果:
函数运行结束
函数的运行时间:2.0001142024993896
这是test的返回值
'''
实例3(Python3.0+):
实例2中虽然已经实现了装饰器的功能,但是被修饰的函数是没有形参的,如果我们在被修饰的函数中定义形参呢,那实例2中的装饰器就不能完成这个任务了吧??
# 带参数的装饰器
#
import time
# 装饰器的架子:高阶函数+函数嵌套+闭包
def timer(func): # func=test
def wrapper(*args,**kwargs): # 相当于定义函数 def test(*args,**wargs):
start_time=time.time()
res=func(*args,**kwargs) # 就是在运行test()
# print(func)
# func() # 就是在运行test()
stop_time=time.time()
print('函数的运行时间:%s' %(stop_time-start_time))
return res
return wrapper # test=wrapper
@timer # test = timer(test)
def test(name,age):
time.sleep(2)
print('函数运行结束')
print('test函数运行完毕,名字是%s 年龄是%s' %(name,age))
return '这是test的返回值'
# test()
print(test('lvcm',19))
'''
运行结果:
函数运行结束
test函数运行完毕,名字是lvcm 年龄是19
函数的运行时间:2.0001144409179688
这是test的返回值
'''
二 练习题:
1、模仿京东商城登录
# 简单的京东登录架构
# 进入京东主页
def index():
print('欢迎来到京东主页')
# 进入个人主页
def home(name):
print('欢迎回家%s' %name)
# 打印购物车物品
def shopping_car(name):
print('%s购物车里有[%s,%s,%s]'%(name,'丝袜','娃娃','奶茶'))
# 打印个人订单
def order():
print('您的订单是.......')
index()
home('lvcm')
shopping_car('lvcm')
order()
# 需求:给每个函数加上一个用户登录的验证功能
#
# 定义用户默认登录状态
dict_user={'username':None,'login':False}
# 定义用户登录验证装饰器
def auth_login(func):
def wrapper(*args,**kwargs):
# print('您未登录,请先登录,谢谢...')
while True:
if dict_user['username']=='lvcm' and dict_user['login'] == True:
res=func(*args,**kwargs)
return res
user_name=input('请输入用户名:').strip()
user_passwd=input('请输入密码:').strip()
if user_name=='lvcm' and user_passwd=='123':
print('%s登录成功' %user_name)
dict_user['username']=user_name
dict_user['login']=True
break
else:
print("用户名密码错误,请重新输入")
res=func(*args,**kwargs)
return res
return wrapper
@auth_login
def index():
print('欢迎来到京东主页')
@auth_login
def home(name):
print('欢迎回家%s' %name)
@auth_login
def shopping_car(name):
print('%s购物车里有[%s,%s,%s]'%(name,'丝袜','娃娃','奶茶'))
@auth_login
def order():
print('您的订单是.......')
index()
'''
运行结果:
请输入用户名:lvcm
请输入密码:123
lvcm登录成功
欢迎来到京东主页
'''
home('lvcm')
'''
运行结果:
请输入用户名:lvcm
请输入密码:123
lvcm登录成功
欢迎回家lvcm
'''
shopping_car('lvcm')
'''
运行结果:
请输入用户名:lvcm
请输入密码:123
lvcm登录成功
lvcm购物车里有[丝袜,娃娃,奶茶]
'''
order()
'''
运行结果:
请输入用户名:lvcm
请输入密码:123
lvcm登录成功
您的订单是.......
'''
上述例题中我们模仿了京东个人登录验证功能,但是代码中发现一个很有意思的问题,就是没次刷新页面时都要验证登录,这是很不合理的,其实登录验证一次就可以了。
2、复杂的仿京东程序
# 定义用户列表
user_list=[
{'name':'lvzf','passwd':'123'},
{'name':'zhangjm','passwd':'123'},
{'name':'lvcm','passwd':'123'},
{'name':'muyb','passwd':'123'},
]
# 定义用户登录初始状态
current_dict={'username':None,'login':False}
def auth_login(func):
def wrapper(*args,**kwargs):
# print('您未登录,请先登录,谢谢...')
while True:
if current_dict['username'] and current_dict['login']:
res=func(*args,**kwargs)
return res
username=input('请输入用户名:').strip()
userpasswd=input('请输入密码:').strip()
for user_dict in user_list:
if username==user_dict['name'] and userpasswd==user_dict['passwd']:
print('%s登录成功' %username)
current_dict['username']=username
current_dict['login']=True
break
else:
print("用户名密码错误,请重新输入")
res=func(*args,**kwargs)
return res
return wrapper
print('before is ')
@auth_login
def index():
print('欢迎来到京东主页')
@auth_login
def home(name):
print('欢迎回家%s' %name)
@auth_login
def shopping_car(name):
print('%s购物车里有[%s,%s,%s]'%(name,'丝袜','娃娃','奶茶'))
@auth_login
def order():
print('您的订单是.......')
index()
home('lvcm')
shopping_car('lvcm')
order()