装饰器
闭包
定义:如果在一个内部函数里,对在外部作用域(但不是在全局作用域)的变量进行引用,那么内部函数就被认为是闭包
闭包程序示例:
def outer():
a=1
def inner(): #条件一:inner是一个内部函数
print(a) #条件二:外部环境的一个变量
return inner #内部函数inner就是一个闭包
outer()
print('-----')
f=outer()
f()
执行结果:
-----
1
Process finished with exit code 0
闭包=函数块+定义函数时的环境
计算代码块的执行时间示例:
import time
def foo():
start = time.time()
print("foo....")
time.sleep(1)
end = time.time()
print('spend %s' % (end - start))
foo()
执行结果:
foo....
spend 1.0002479553222656
Process finished with exit code 0
装饰器的应用示例
装饰器应用初期示例:
import time
def foo():
print("foo....")
def bar():
print("bar....")
def show_time(func): #对于这个函数实现的功能就是计算其他函数的执行时间
start = time.time() #所以我们希望传入的参数就是函数名称
func()
time.sleep(1)
end = time.time()
print('spend %s' % (end - start))
print('next'.center(30,'-'))
show_time(foo) #这里在执行时间计算函数是传参函数名称即可
show_time(bar)
执行结果:
foo....
spend 1.0002162456512451
-------------next-------------
bar....
spend 1.0001883506774902
-------------next-------------
Process finished with exit code 0
-
对于函数的封闭性,像上面的功能计算函数的执行时间,可以在源函数中加新的计算时间的代码,但是不建议修改原函数中的代码块,所以这里重新创建一个时间计算功能的函数,向时间计算函数中传参,参数就是其他需要计算时间的函数名称,这样就可以用一个时间计算函数计算多个函数的执行时间,没有破坏原函数的代码块,也减少了代码的冗余。
-
但是上图中的程序,虽然实现了计算函数执行时间的功能,但是改变了函数的调用方式,也就是说,原来的函数调用方式是foo()但是现在的调用方式变成了show_time(foo),如果对于旧程序的修改,可能涉及到很多调用函数的地方,这时候全部修改函数的调用方式就非常的麻烦,这里建议使用下面的装饰器的方法。
装饰器的真实应用示例:
import time
def foo():
print("foo....")
def bar():
print("bar....")
def show_time(func): #这里使用的就是inner这个闭包,因为inner是一个闭包,可以在调用inner的时候,读取到func参数的值
def inner():
start = time.time()
func()
time.sleep(1)
end = time.time()
print('spend %s' % (end - start))
print('next'.center(30,'-'))
return inner
foo=show_time(foo) #再使用这里的转换
bar=show_time(bar)
foo() #最终实现计算函数执行时间,同时又不改变函数的调用方式
bar()
执行结果:
foo....
spend 1.0014970302581787
-------------next-------------
bar....
spend 1.0007696151733398
-------------next-------------
Process finished with exit code 0
对以上程序的优化
import time
def show_time(func):
def inner():
start = time.time()
func()
time.sleep(1)
end = time.time()
print('spend %s' % (end - start))
print('next'.center(30,'-'))
return inner
@show_time #等同于foo=show_time(foo) #也是一种调用装饰器的方式
def foo():
print("foo....")
@show_time #等同于bar=show_time(bar)
def bar():
print("bar....")
foo()
bar()
执行结果:
foo....
spend 1.0006310939788818
-------------next-------------
bar....
spend 1.0006492137908936
-------------next-------------
Process finished with exit code 0
装饰器实现加法器的程序代码:
import time
def show_time(func):
def inner(x,y):
start = time.time()
func(x,y)
end = time.time()
print('spend %s' % (end - start))
print('next'.center(30,'-'))
return inner
@show_time
def add(a,b):
print(a+b)
time.sleep(1)
add(1,3)
执行结果:
4
spend 1.0006909370422363
-------------next-------------
Process finished with exit code 0
进阶:传入不定长参数
import time
def show_time(func):
def inner(*args):
start = time.time()
func(*args)
end = time.time()
print('spend %s' % (end - start))
print('next'.center(30,'-'))
return inner
@show_time
def add(*args):
sum=0
for i in args:
sum = sum + i
print(sum)
time.sleep(1)
add(1,3,9,11,98,256,199)
执行结果:
577
spend 1.000802755355835
-------------next-------------
Process finished with exit code 0
装饰器参数
- 需求描述:用户输入参数,如果用户输入的为true,则写入日志,如果用户输入非true,则不输出日志
程序示例:
import time
def logger(flag):
def show_time(func):
def inner(*args):
start = time.time()
func(*args)
end = time.time()
print('spend %s' % (end - start))
print('next'.center(30,'-'))
if flag == 'true':
print("log is loaded!") #这里使用print模拟写入日志
return inner
return show_time
rst=input(">>>:")
@logger(rst)
def add(*args):
sum=0
for i in args:
sum = sum + i
print(sum)
time.sleep(1)
add(1,3,9,11,98,256,199)
执行结果:
>>>:true
577
spend 1.0006272792816162
-------------next-------------
log is loaded!
Process finished with exit code 0
>>>:false
577
spend 1.0006201267242432
-------------next-------------
Process finished with exit code 0