本章目录:
装饰器:
一、为什么要用装饰器
二、什么是装饰器
三、无参装饰器
四、装饰器语法糖
五、认证装饰器实现
六、叠加多个装饰器
七、带参装饰器
===========================================================
一、开放封闭原则
引子--为什么要用装饰器
软件一旦上线后,对修改源代码是封闭的,对功能扩展是开放的。
也就是说我们必须找到一种解决方案:
能够在不修改一个功能源代码以及调用方式的前提下,为其加上新功能
总结,原则如下:
1、不修改源代码
2、不修改调用方式
目的:
在原则1&2的基础上扩展新功能
二、什么是装饰器
装饰器(Decorator)是一种特殊的函数,用来给函数添上新功能的函数。
主要用于抽离大量函数中与函数本身无关的雷同代码并继续重用。
装饰器又可分为带参数和不带参数。
完整含义:
装饰器即在不修改被装饰对象源代码与调用方式的前提下,为被装饰器对象添加新功能
装饰器与被装饰对象均可以是任意可调用的对象
装饰器>>>函数
被装饰的对象>>>函数
三、装饰器实现之无参装饰器
装饰器的实现不能脱离,不能修改源代码,不能修改源调用方式的原则。下面我们将按照实现装饰器的思路,一步一步实现装饰器。
为下面的程序增加运行计时功能。
import timedef index(): time.sleep() print('This is Index Page!')
方案1:
import timedef index(): start_time=time.time() time.sleep(3) print('welcome to index page') stop_time=time.time() print('run time is %s' %(stop_time-start_time))index()
# 该方案虽然达到了计时功能,但是修改了源代码,违背了装饰器两大原则
方案2:
import time #引入时间包,方便调用time()方法def index(): time.sleep(2) print('This is Index Page.')start_time = time.time()index()stop_time = time.time()print('The running time is %s' % (stop_time - start_time)
# 该方案虽然达到了计时功能,但是只是针对的增加代码,如果别的程序也要计时,还要重写一次,无法复用。
方案3:
import timedef index(): time.sleep(2) print('This is Index Page')def wrapper(): start_time = time.time() index() stop_time = time.time() print('The running time is %s' % (stop_time - start_time))
# 该方案虽然达到了计时功能,但是要显示计时,还要去调用wrapper(),更改了原函数的调用方式
方案4:
import timedef index(): time.sleep(2) print('This is Index Page')def wrapper(func): #func = index start_time = time.time() func(); #index stop_time = time.time() print('The running time is %s' % (stop_time, start_time))wrapper(index)
# 该方案虽然达到了计时功能,但是要显示计时,不仅要调用wrapper(), 而且需要把原函数index作为参数导入,更改了原函数的调用方式
方案5(步入正轨之无参装饰器):
import timedef index(): time.sleep() print('This is Index Page')def outter(func): # func = 最初始的index # func = index 巧用闭包,传递参数, # 外部函数带的参数,就是准备给内部函数里用的,这里是闭包功能 def wrapper(): start_time = time.time() func() stop_time = time.time() print('The running time is %s') return wrapperindex = outter(index) #初始index函数经过处理已经被变更为outter(index),被''装饰''了index()
# 该方法能显示运行时长, 是把最初始的index函数通过闭包的特点,经过处理后重新把新的函数内存地址,赋值给了index,后面的index函数已经不是最初的index,它经过被''装饰''了
方案6(方案5的升级版):
1. 无参装饰器,引入带参函数的时候出现了错误。
# 不同于index()函数,这次我们引入一个新函数,带参数call_you(name)import timedef call_you(name): time.sleep(2) print('I call you %s' %name)def outter(func): def wrapper(name): start_time = time.time() res = func(name) stop_time = time.time() print('The running time is %s' % (stop_time - start_time) return res return wrapperindex = outter(index)home = outter(home) #home带参,但是index不带参,这里运行会报错
方案7(解决方案6的问题):
# 运用可变长度参数处理这个问题
# 可变长度参数模版,注意参数是*args **kwargsdef outter(func): def inner(*args, **kwargs): res = func(*args, ** kwargs) return res return inner
import timedef call_you(name): time.sleep(2) print('I call you %s' %name)def outter(func): def wrapper(*args, **kwargs): start_time = time.time() res = func(*args, **kwargs) stop_time = time.time() print('The running time is %s' %(stop_time - start_time)) return res return wrapper call_you = outter(call_you)call_you('Puppy')
四、装饰器语法糖
语法糖意指那些没有给计算机添加新功能,只是对人类来说更加“甜蜜”的语法,能够增加程序的可读性,减少代码出错的机会。
# 注意语法糖的放置位置,放在要用的函数的顶部,要用@开头
五、认证装饰器实现
1. 加入认证模块的简单实现:
2. 加入认证模块后登陆进行验证:
# 注意多个装饰器的顺序,按照顺序执行
1. 认证装饰器
2. 计时装饰器
3. 叠加多个装饰器(注意先后顺序)