装饰器
一 装饰器介绍
1.1为何要用装饰器
开放封闭原则:软件一旦上线运行后,应该对修改源代码进行封闭,对拓展空能开放
原则:
1、不修改函数内的源代码
2、不修改函数的调用方式
装饰器就是在遵循原则1和2的前提下,为被装饰对象添加上新功能。
软件的设计应该遵循开放封闭原则,即对扩展是开放的,而对修改是封闭的。对扩展开放,意味着有新的需求或变化时,可以对现有代码进行扩展,以适应新的情况。对修改封闭,意味着对象一旦设计完成,就可以独立完成其工作,而不要对其进行修改。
软件包含的所有功能的源代码以及调用方式,都应该避免修改,否则一旦改错,则极有可能产生连锁反应,最终导致程序崩溃,而对于上线后的软件,新需求或者变化又层出不穷,我们必须为程序提供扩展的可能性,这就用到了装饰器
1.2什么是装饰器
装饰器就是一个用来为被装饰对象添加新功能的工具
装饰器就是一个用来为被装饰对象添加新功能的工具
装饰器就是一个用来为被装饰对象添加新功能的工具
!!!
装饰器就是闭包函数的一种应用场景
’装饰’代指为被装饰对象添加新的功能,’器’代指器具/工具,装饰器与被装饰的对象均可以是任意可调用对象。概括地讲,装饰器的作用就是在不修改被装饰对象源代码和调用方式的前提下为被装饰对象添加额外的功能。装饰器经常用于有切面需求的场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等应用场景,装饰器是解决这类问题的绝佳设计,有了装饰器,就可以抽离出大量与函数功能本身无关的雷同代码并继续重用。
提示:可调用对象有函数,方法或者类,此处我们单以本章主题函数为例,来介绍函数装饰器,并且被装饰的对象也是函数。
二 装饰器的实现
函数装饰器分为:无参装饰器和有参装饰器
2.1无参装饰器的实现
# 需求:为函数index运行统计运行时间
# import time
# def index():
# time.sleep(1)
# print('from index')
# index()
# 方案一:
# import time
# def index():
# start=time.time()
# time.sleep(1)
# print('from index')
# stop=time.time()
# print('run time is %s' %(stop-start))
# index()
#改了源代码
# 方案二:
# import time
# def index():
# time.sleep(1)
# print('from index')
#
# start=time.time()
#
# index()
# stop = time.time()
# print('run time is %s' % (stop - start))
# 重复代码
# 方案三:
# import time
# def index():
# time.sleep(1)
# print('from index')
#
# def wrapper(func):
# start=time.time()
# func()
# stop = time.time()
# print('run time is %s' % (stop - start))
# wrapper(index)
#调用方式发生改变
# 方案四:#用闭包函数
# import time
# def index():
# time.sleep(1)
# print('from index')
# def timer(func):
# def wrapper():
# start = time.time()
# func()
# stop = time.time()
# print('运行时间为%s' %(stop-start))
# return wrapper
# index = timer(index)
# index()
用闭包函数可以实现装饰器的要求进一步完善>>>
# 方案六:====》将wrapper伪装成被装饰的函数,那么应该装的尽可能像一些
import time
def index(): # index = 被装饰对象index函数的内存地址
time.sleep(1)
print('from index')
def home(name):
time.sleep(2)
print("welcome %s to home page" %name)
return 123
def outter(func): # func = 被装饰对象index函数的内存地址
def wrapper(*args,**kwargs):
start = time.time()
res = func(*args,**kwargs) # 被装饰对象index函数的内存地址(x,y,z)
stop = time.time()
print('run time is %s' %(stop - start))
return res
return wrapper # 千万别加括号
index = outter(index) # outter(被装饰对象index函数的内存地址) -> 返回wrapper函数的内存地址---> index = wrapper函数的内存地址
home = outter(home)
# print(index)
res = home("egon") # wrapper("egon")
print(res)
res = index() # wrapper()
print(res)
2.2有参装饰器的实现
无
2.3装饰器语法糖
import time
from functools import wraps
def outter(func): # func = 被装饰对象index函数的内存地址
@wraps(func)
def wrapper(*args,**kwargs):
start = time.time()
res = func(*args,**kwargs) # 被装饰对象index函数的内存地址(x,y,z)
stop = time.time()
print('run time is %s' %(stop - start))
return res
return wrapper # 千万别加括号
@outter # index = outter(index) # outter(被装饰对象index函数的内存地址) -> 返回wrapper函数的内存地址---> index = wrapper函数的内存地址
def index(): # index = 被装饰对象index函数的内存地址
"""这是index函数"""
time.sleep(1)
print('from index')
@outter # home = outter(home)
def home(name):
time.sleep(2)
print("welcome %s to home page" %name)
return 123
print(index.__name__)
print(index.__doc__)
2.4无参装饰器模板
# 无参装饰器的模板
# def outter (func):
# def wrapper(*args,**kwargs):
# res=func(*args,**kwargs)
# return res
# return wrapper
# 无参装饰器的模板+语法糖 #作用见上面语法糖介绍
from functools import wraps
def outter (func):
@wrapper(func)
def wrapper(*args,**kwargs):
res=func(*args,**kwargs)
return res
return wrapper
#加认证功能
# def login (func ):
# def wrapper(*args,**kwargs):
# for x in range(3):
# name=input('username>>>:').strip()
# pwd=input('password>>>:').strip()
#
# if name == 'william' and pwd =='123':
# res=func(*args,**kwargs)
# return res
# else:
# print('输入错误')
# return wrapper
#
# @login
# def index():
# print('登录成功')
#
# index()
2.5叠加多个装饰器
def deco1(func1): # func1 = wrapper2的内存地址
def wrapper1(*args,**kwargs):
print('===========>wrapper1')
res1=func1(*args,**kwargs)
print('end1')
return res1
return wrapper1
def deco2(func2): # func1 = wrapper3的内存地址
def wrapper2(*args,**kwargs):
print('===========>wrapper2')
res2=func2(*args,**kwargs)
print('end2')
return res2
return wrapper2
def deco3(func3): # func1 = index的内存地址
def wrapper3(*args,**kwargs):
print('===========>wrapper3')
res3=func3(*args,**kwargs)
print('end3')
return res3
return wrapper3
# index=wrapper1的内存地址
@deco1 # deco1 (wrapper2的内存地址)->wrapper1的内存地址
@deco2 # deco2(wrapper3的内存地址) -> wrapper2的内存地址
@deco3 #deco3(被装饰的index的内存地址) -> wrapper3的内存地址
def index():
print('from index')
index()