写代码要遵循开发封闭原则,虽然在这个原则是用的面向对象开发,但是也适用于函数式编程,简单来说,它规定已经实现的功能代码不允许被修改,但可以被扩展,即:
- 封闭:已实现的功能代码块
- 开放:对扩展开发
故装饰器的出现就是解决以上问题的
一、什么是装饰器
装饰器本质就是函数,功能是为其他函数附加功能
二、装饰器遵循的原则
1、不修改被修饰函数的源代码
2、不修改被修饰函数的调用方式
三、实现装饰器的知识储备
装饰器=高阶函数+函数嵌套+闭包
装饰器的简单示例1:(在不修改源代码的基础上添加新的功能)
import time
def timmer(func):
def wrapper():
print(func)
func()
return wrapper
@timmer#就相当于是装饰器的功能,将被装饰的index加入了新功能,即index=timmer(index)#
def index():
time.sleep(2)
print("welcome to beijing")
index()
执行结果是:
<function index at 0x000000000251B8C8>
welcome to beijing
装饰器示例2:(在不修改源代码的基础上添加计算运行时间的新的功能)
# #计算运行时间
import time#导入模块
def timmer(func):#这时候相当于def timmer(func)是def timmer(index)
def wrapper():
print(func) #打印index的内存地址
start_time=time.time()#开始时间
func() #func()相当于index()#相当于执行index()原始函数
stop_time=time.time()#结束时间
print("run time is %s"%(stop_time-start_time))#第八步
return wrapper#
@timmer#是装饰器的功能,将被装饰的index加入了新功能,即index=timmer(index)
def index():
time.sleep(2)
print("welcome to beijing")
index()#由于上面def index()是def timmer(index)(),timmer(index)的执行结果是wrapper,
# 故而执行index函数就相当于是执行wrapper()
执行结果是:
<function index at 0x00000000024CB8C8>
welcome to beijing
run time is 2.0001144409179688
如图示例:
什么叫高阶函数呢??
高阶函数定义:
1.函数接收的参数是一个函数名
2.函数的返回值是一个函数名
3.满足上述条件任意一个,都可称之为高阶函数
高阶函数示例1:(函数接受的参数是一个函数名)
def foo():
print('from foo')
def foo_1(func):
print('from foo_1')
func()
def foo_2(func):
print('from foo_2')
return func
foo_1(foo)#将函数名foo当做参数
foo_2(foo)#将函数名foo当做参数
执行结果是:
from foo_1
from foo
from foo_2
高阶函数示例2:(函数的返回值是一个函数名)
def foo():
print('from foo')
def foo_1(func):
print('from foo_1')
func()
return func
foo=foo_1(foo)
print(foo)
执行结果是:
from foo_1
from foo
<function foo at 0x0000000001D13E18>
高阶函数总结
1.函数接收的参数是一个函数名
作用:在不修改函数源代码的前提下,为函数添加新功能,
不足:会改变函数的调用方式
2.函数的返回值是一个函数名
作用:不修改函数的调用方式
不足:不能添加新功能
装饰器:
无参装饰器:
示例1:
import time
def timmer(func):
def wrapper(*args,**kwargs):
print(func)#打印的是home的内存地址
start=time.time()
func(*args,**kwargs)#由于func为home,故而返回下面执行home函数,即home(“xuyuanyuan”)
stop=time.time()
print('run time is %s ' %(stop-start))
return wrapper
@timmer#相当于home=timmer(home)
def home(name):
time.sleep(2)
print('welcome to %s home page' %name)
home('xuyuanyuan')#执行的是wrapper(“xuyuanyuan”),将xuyuanyuan当做参数传给wrapper(*args,**kwargs)这个函数
执行结果是:
<function home at 0x000000000254B8C8>
welcome to xuyuanyuan home page
run time is 2.0011146068573
示例2:
##无参装饰器(有参函数)
import time
def timmer(func):
def wrapper(*args,**kwargs):#wrapper('egon','123')
start_time=time.time()
func(*args,**kwargs) #相当于执行该auth('egon','123')函数,将egon 123当做参数传给函数auth(name,password),故而输出print('egon','123')
stop_time=time.time()
print('run time is %s' %(stop_time-start_time))
return wrapper
@timmer #auth=timmer(auth)
def auth(name,password):
print(name,password)
auth('egon','123') #wrapper('egon','123')
执行结果是:
egon 123
run time is 0.0
示例3:
##判断最大值,并输出它的运行时间
import time
def timmer(func):#相当于def timmer(my_max)
def wrapper(*args,**kwargs):
start_time=time.time()
res=func(*args,**kwargs) #my_max(1,2)
stop_time=time.time()
print('run time is %s' %(stop_time-start_time))
return res
return wrapper
@timmer#my_max=timmer(my_max)
def my_max(x,y):
print('my_max function')
res=x if x > y else y
return res
res=my_max(1,2) #res=wrapper(1,2)
print('=====>',res)
执行结果是:
my_max function
run time is 0.0
=====> 2
有参装饰器(即2层闭包函数)
示例:
def auth2(auth_type):
def auth(func):
# print(auth_type)
def wrapper(*args,**kwargs):
if auth_type == 'file':
with open("file.txt", mode="r", encoding="utf8") as f:
file_list = f.readlines()
name=input('用户名: ')
passwd=input('密码:')
if name in file_list: # 如果用户名在黑名单内
print("您的账户已锁定,请联系管理员!")
if name == 'xyy' and passwd == '123':
print('auth successfull')
res=func(*args,**kwargs)#执行函数index()
return res
else:
print('auth error')
elif auth_type == 'sql':
print('暂不支持')
return wrapper
return auth
@auth2(auth_type='file') #auth2(auth_type='sql')的返回结果是author,故而@auth 相当于#index=auth(index)
def index():
print('welcome to inex page')
index()#运行函数index
执行结果是:
用户名: xyy
密码:123
auth successfull
welcome to inex page
多个装饰器的使用:
当需要使用多个装饰器的功能时,一般是先调用下面的@,再执行上面的@
举例说明:(给上述例子加入计算运行时间的功能)
import time#导入时间模块
current_login={'name':None,'login':False}
##定义运行时间函数
def timmer(func):
def wrapper(*args,**kwargs):
start_time=time.time()
res=func(*args,**kwargs)
stop_time=time.time()
print('run time is %s' %(stop_time-start_time))
return res
return wrapper
##定义用户登录调用账号密码的方式(文件还是数据库)
def auth2(auth_type='file'):
def auth(func):
# print(auth_type)
def wrapper(*args,**kwargs):
if current_login['name'] and current_login['login']:
res=func(*args,**kwargs)
return res
if auth_type == 'file':
name=input('username: ')
password=input('password: ')
if name == 'xyy' and password == '123':
print('auth successfull')
res=func(*args,**kwargs)
current_login['name']=name
current_login['login']=True
return res
else:
print('auth error')
elif auth_type == 'sql':
print('暂不支持')
return wrapper
return auth
##调用了2个装饰器,先执行@auth2(auth_type='file')再运行@timmer,由上至下
@timmer##再执行这个
@auth2(auth_type='file') #@auth #index=auth(index)##先执行这个
def index():
print('welcome to inex page')
index()
执行结果是:
username: xyy
password: 123
auth successfull
welcome to inex page
run time is 12.809732437133789
welcome to inex page
run time is 0.0