装饰器
原理:装饰器说到底就是闭包的多层运用,内部调用外层函数的局部变量返回给外部函数再在全局调用结果。
原则:1.封闭开放原则。2.把写的基础函数(别人或者各个模块调用)封闭起来不做更改。3.需要增加功能时,可以拓展。
@语法:加上@符 系统会自动把下面的函数当成参数传到装饰器中,从下到上。
功能举例:假如我们在工作中写的某个功能,已经在生产线上使用了,然后那些前端工作者调用我们的功能函数。但后期需要在原来的基础上添加新功能而不修改原函数的代码,调用时还继续用原函数的名字。
1.装饰器
比如我们有一个功能模块是打印出来一句话,但这个功能使用一段时间后客户在原来的基础上增加了想显示运行时间的新需求。我们想了一下,这个简单,我可以遵守封闭开放原则的同时,把原函数放在一个新函数里,这样就满足了需求。我们虽然把需求满足了,但是前端调用者不知道我们改函数名了,而且他们也已经习惯原来的调用方式。这就用到了装饰器:
import time
#定义一个装饰器
def show_time(f):
def inner():
start_time = time.time() #开始时间
f() #运行原函数
end_time = time.time() #结束时间
print("spend %s"%(end_time-start_time)) #所用时间差
return inner
def foo(): #原函数执行一个操作
print("fo......")
time.sleep(3) #间停三秒
foo = show_time(foo) #将原函数传入拓展功能函数 foo = inner
foo() #再调用原函数名,从而实现不改函数名再增加新的功能 foo() = inner()
#这次我们运用@语法
@show_time #bar = show_time(bar)
def bar():
print("ba.....")
time.sleep(3)
bar()
2.被装饰函数的参数
如果被装饰函数需要传入不定长参数,那将在装饰函数中也做出相应的传参改变。
我们定义一个加法装饰器,需要传入多个参数,然后打印出程序运算的时间。
import time
def show_time(f):
def inner(*args): #传入功能函数不定长参数
start_time = time.time()
f(*args) #被装饰函数传入不定长参数
end_time = time.time()
print("spend %s"%(end_time-start_time))
return inner
@show_time
def add(*args): #给功能函数加不定长参数
sum = 0
for i in args:
sum+=i
print(sum)
time.sleep(1)
add()
3.带参数的装饰器
如果我们在用到装饰器的时候,里面有个功能,我们想给出信号就使用,不给信号不使用。
举个栗子吧:我们每次用到加法器的时候需要打印一次使用日志,不使用则不打印。
import time
def logger(flag=''): #打印日志,默认为空
def show_time(f):
def inner(*args): #传入功能函数不定长参数
start_time = time.time()
f(*args) #被装饰函数传入不定长参数
end_time = time.time()
print("spend %s"%(end_time-start_time))
if flag = 'true': #有对应的参数就调用日志功能
print("打印使用日志")
return inner
return show_time
@logger('true')
def add(*args): #给功能函数加不定长参数
sum = 0
for i in args:
sum+=i
print(sum)
time.sleep(1)
add()
@logger()
def fo():
print('fo....')
time.sleep(3)
fo()
注意:我们在使用带有参数的装饰器的时候,不用担心最外层函数的影响。它只起到一个框架的作用,并不影响原来装饰器的使用,只要注意参数的传入和内部函数接收到参数时做判断后给出的动作,也可以有多个不同动作,这个看个人需求。