在说装饰器之前先要理解一个概念,即《开放封闭原则》。
开放封闭原则(OCP,Open Closed Principle)是所有面向对象原则的核心。软件设计本身所追求的目标就是封装变化、降低耦合,而开放封闭原则正是对这一目标的最直接体现。其他的设计原则,很多时候是为实现这一目标服务的,例如以Liskov替换原则实现最佳的、正确的继承层次,就能保证不会违反开放封闭原则。
写代码要遵循《开放封闭原则》,简单来说他规定已经实现的功能代码不允许被修改,但可以被扩展,即:
软件实体应该是可扩展,而不可修改的。也就是说,对扩展是开放的,而对修改是封闭的。
因此,开放封闭原则主要体现在两个方面:
- 对扩展开放,意味着有新的需求或变化时,可以对现有代码进行扩展,以适应新的情况。
- 对修改封闭,意味着类一旦设计完成,就可以独立完成其工作,而不要对类进行任何修改。
案例一简单应用(无参):
现有如下代码:
实现计算随机数和的计算。
import random
def sum_1():
sum_temp=0
num=random.randint(1,99)
for i in range(0,num):
sum_temp=sum_temp+i
print("计算1-%s的和"%(num-1))
print(sum_temp)
if __name__=="__main__":
sum_1()
现新增需求点,要求计算该段代码的执行时间:
实现方式一:
import random,time
def sum_1():
start_time=time.time()
sum_temp=0
num=random.randint(1,99)
for i in range(0,num):
sum_temp=sum_temp+i
end_time=time.time()
print("计算1-%s的和"%(num-1))
print(sum_temp)
print("程序执行时间:%s秒"%((end_time-start_time)*1000))
if __name__=="__main__":
sum_1()
#执行结果:
#计算1-48的和
#1176
#程序执行时间:1.0008811950683594秒
问题点:
1、违反《开放封闭原则》,已实现功能的代码不允许改动
2、如该段代码为核心业务支撑,供各子业务系统调用,如改动出现问题将影响所有相关业务系统的使用,风险较大。
实现方式二(使用装饰器):
import random,time
def sum_1_deco(func):
def wrapper():
start_time=time.time()
func()
end_time=time.time()
print("程序执行时间:%s秒"%((end_time-start_time)*1000))
return wrapper #注意不加()
@sum_1_deco
def sum_1():
sum_temp=0
num=random.randint(1,99)
for i in range(0,num):
sum_temp=sum_temp+i
print("计算1-%s的和"%(num-1))
print(sum_temp)
if __name__=="__main__":
sum_1()
#执行结果:
#计算1-73的和
#2701
#程序执行时间:0.5004405975341797秒
可以看到在以上代码中实现了相同的功能,但并未改动原有已实现功能的代码
案例二简单应用(有参):
假设现有核心业务程序,该段程序用于在核心业务系统中获取相关业务数据供各子业务系统进行调用,如下:
type_dict={ 1:'销售数据',
2:'财务数据',
3:'客户数据',
}
def core(*args,**kwargs):
print("用户:%s 获取数据:%s"%(kwargs['user'],type_dict[kwargs['data_type']]))
if __name__=="__main__":
core(data_type=1,user="admin")
#执行结果
#用户:admin 获取数据:销售数据
该段代码承载核心业务数据,出于信息安全考虑,信息安全管理部门要求对调用该程序的各子业务系统进行安全验证,仅有部分用户可以调用。
实现方式一:
type_dict={ 1:'销售数据',
2:'财务数据',
3:'客户数据',
}
# def core(*args,**kwargs):
# print("用户:%s 获取数据:%s"%(kwargs['user'],type_dict[kwargs['data_type']]))
user_list=["admin","admin1","admin2"]
def core(*args,**kwargs):
if kwargs['user'] in user_list:
print("用户:%s 获取数据:%s"%(kwargs['user'],type_dict[kwargs['data_type']]))
else:
print("用户:%s 权限验证失败!!!"%kwargs['user'])
if __name__=="__main__":
print("-"*50)
core(data_type=1,user="admin")
print("-"*50)
core(data_type=2,user="user")
#执行结果
#--------------------------------------------------
#用户:admin 获取数据:销售数据
#--------------------------------------------------
#用户:user 权限验证失败!!!
实现方式二(使用装饰器):
type_dict={ 1:'销售数据',
2:'财务数据',
3:'客户数据',
}
user_list=["admin","admin1","admin2"]
def core_deco(func):
def wrapper(*args,**kwargs):
if kwargs['user'] in user_list:
func(*args,**kwargs)
else:
print("用户:%s 权限验证失败!!!"%kwargs['user'])
return wrapper
@core_deco
def core(*args,**kwargs):
print("用户:%s 获取数据:%s"%(kwargs['user'],type_dict[kwargs['data_type']]))
if __name__=="__main__":
print("-"*50)
core(data_type=1,user="admin")
print("-"*50)
core(data_type=2,user="user")
#执行结果:
#--------------------------------------------------
#用户:admin 获取数据:销售数据
#--------------------------------------------------
#用户:user 权限验证失败!!!
python装饰器的执行时间:
- 只要python解释器执行到了这段代码那么就会自动进行装饰,而不是等到python调用该段代码时才进行装饰