Python装饰器
1为何要使用装饰器
软件的设计应该遵循开放封闭原则,即对扩展是开放的,而对修改是封闭的。对扩展开放,意味着有新的需求或变化时,可以对现有代码进行扩展,以适应新的情况。对修改封闭,意味着对象一旦设计完成,就可以独立完成其工作,而不要对其进行修改。软件包含的所有功能的源代码以及调用方式,都应该避免修改,否则一旦改错,则极有可能产生连锁反应,最终导致程序崩溃,而对于上线后的软件,新需求或者变化又层出不穷,我们必须为程序提供扩展的可能性,这就用到了装饰器。
2什么是装饰器
’装饰’代指为被装饰对象添加新的功能,’器’代指器具/工具,装饰器与被装饰的对象均可以是任意可调用对象。概括地讲,装饰器的作用就是在不修改被装饰对象源代码和调用方式的前提下为被装饰对象添加额外的功能。装饰器经常用于有切面需求的场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等应用场景,装饰器是解决这类问题的绝佳设计,有了装饰器,就可以抽离出大量与函数功能本身无关的雷同代码并继续重用。提示:可调用对象有函数,方法或者类,此处我们单以本章主题函数为例,来介绍函数装饰器,并且被装饰的对象也是函数。
3装饰器的实现
函数装饰器分为:无参装饰器和有参装饰两种,二者的实现原理一样,都是’函数嵌套+闭包+函数对象’的组合使用的产物。
3.1无参装饰器
#1、 *args, **kwargs
def index(x,y):
print(x,y)
def wrapper(*args,**kwargs):
index(*args,**kwargs) #
# index(y=222,x=111)
wrapper(y=222,x=111) #为wrapper传参的格式会原封不动的转嫁给index()
# 2、名称空间与作用域:名称空间的的"嵌套"关系是在函数定义阶段,即检测语法的时候确定的
# 3、函数对象:
# 可以把函数当做参数传入
# 可以把函数当做返回值返回
def index():
return 123
def foo(func):
return func
foo(index)
# 4、函数的嵌套定义:
def outter(func):
def wrapper():
pass
return wrapper
# 闭包函数
def outter(): #让闭包函数返回到全局的地位
x=111
def wrapper():
x
return wrapper
f=outter()
# 传参的方式一:通过参数的形式为函数体传值
def wrapper(x):
print(1)
print(2)
print(3)
x
wrapper(1)
wrapper(2)
wrapper(3)
# 传参的方式二:通过闭包的方式为函数体传值
def outter(x):
x=1
def wrapper():
print(1)
print(2)
print(3)
x
return wrapper # return outter内的wrapper那个函数的内地址
f1=outter(1) #投食
f2=outter(2)
f3=outter(3)
wrapper=outter(1) #名字重了没有关系,一个是全局命名空间,一个是局部命名空间
#装饰器
"""
1、什么是装饰器
器指的是工具,可以定义成成函数
装饰指的是为其他事物添加额外的东西点缀
合到一起的解释:
装饰器指的定义一个函数,该函数是用来为其他函数添加额外的功能
2、为何要用装饰器
开放封闭原则
开放:指的是对拓展功能是开放的
封闭:指的是对修改源代码是封闭的
线上运行的软件不能轻易关闭修改
装饰器就是在不修改被装饰器对象源代码以及调用方式的前提下为被装饰对象添加新功能
3、如何用
"""
# 需求:在不修改index函数的源代码以及调用方式的前提下为其添加统计运行时间的功能
def index(x,y):
time.sleep(3)
print('index %s %s' %(x,y))
index(111,222)
# index(y=111,x=222)
# index(111,y=222)
# 解决方案一:失败
# 问题:没有修改被装饰对象的调用方式,但是修改了其源代码
# import time
#
# def index(x,y):
# start=time.time()
# time.sleep(3)
# print('index %s %s' %(x,y))
# stop = time.time()
# print(stop - start)
#
# index(111,222)
# 解决方案二:失败
# 问题:没有修改被装饰对象的调用方式,也没有修改了其源代码,并且加上了新功能
# 但是代码冗余
# import time
#
# def index(x,y):
# time.sleep(3)
# print('index %s %s' %(x,y))
#
# start=time.time()
# index(111,222)
# stop=time.time()
# print(stop - start)
#
#
#
# start=time.time()
# index(111,222)
# stop=time.time()
# print(stop - start)
#
#
# start=time.time()
# index(111,222)
# stop=time.time()
# print(stop - start)
第三种方式:失败
#问题:解决了方案二代码冗余问题,但是带来了一个新问题即函数的调用方式改变了
import time
# def index(x,y):
# time.sleep(3)
# print('index is %s %s' %(x,y))
# def warrper():
# start_time=time.time()
# index(11,12)
# end_time=time.time()
# print(end_time-start_time)
# warrper()
#方案三的优化一:将index的参数写活
# def index(x,y,z):
# time.sleep(3)
# print("index is %s %s %s" %(x,y,z))
# def warrper(*args,**kwargs):
# start_time=time.time()
# index(*args,**kwargs)
# end_time=time.time()
# print(end_time-start_time)
# warrper(11,z=12,y=15)
# 方案三的优化二:在优化一的基础上把被装饰对象写活了,原来只能装饰index,现在谁都可以装饰了
# def index(x,y,z):
# time.sleep(3)
# print("index is %s %s %s" %(x,y,z))
# def home(page):
# time.sleep(2)
# print(page)
# def outter(func):
# #func为函数的内存地址,传入给外层函数
# def wrapper(*args,**kwargs):
# start_time=time.time()
# res=func(*args,**kwargs)
# end_time=time.time()
# print(end_time-start_time)
# return res
# return wrapper
# index=outter(index)
# res=index(11,12,13)
# print(res)
# home=outter(home)
# res=home("刘雨欣呆呆")
# print(res)
#语法糖:让你开心的语法
# def outter(func):
# #func为函数的内存地址,传入给外层函数
# def wrapper(*args,**kwargs):
# start_time=time.time()
# res=func(*args,**kwargs)
# end_time=time.time()
# print(end_time-start_time)
# return res
# return wrapper
# @outter
# def index(x,y,z):
# time.sleep(3)
# print("index is %s %s %s" %(x,y,z))
# @outter
# def home(page):
# time.sleep(2)
# print(page)
#加上语法糖之后就是自动调用
# index(11,22,33)
def timmer(func):
def wrapper(*args,**kwargs):
input_name=input("请输入你的账户")
input_password=input("请输入你的密码")
if 'yanjialuo'==input_name and '123456'==input_password:
res=func(*args,**kwargs)
return res
else:
print("登录失败")
return wrapper
@timmer
def login():
print("您好,您已登录成功")
login()
浙公网安备 33010602011771号