#*********************************** 闭包 ************************************************
定义:如果在一个函数内又定义一个内部函数,内部函数对外层函数的作用域(但不是在全局作用域)的变量进行引用,那么内部函数就被认为是闭包(closure).
def outer():#外层函数
x = 10
def inner():#条件一:inner就是内部函数
print(x)#条件二:内部函数操作外层函数的一个变量
return inner#结论:内部函数inner就是一个闭包
#*********************************** 装饰器 ************************************************
装饰器本质上是一个函数,该函数可以让其他函数在不需要修改代码的前提下增加额外的功能,装饰器的返回值通常是一个被装饰函数的对象。
概括的讲,装饰器的作用就是为已经存在的对象添加额外的功能。
#=================== 简单装饰器实例 ===================
import time
def show_time(func):#装饰器函数,形参为被装饰函数对象
def wrapper():#以闭包形式打造装饰器,方便修改外部环境
start_time=time.time()#记录初始时间戳
ret = func()# 执行形参函数,即被装饰函数
end_time=time.time()#记录终止时间戳
print('spend %s'%(end_time-start_time))#输出运行时间
return ret #返回func函数的执行结果
return wrapper#返回被扩展后的函数对象
@show_time#等价于foo=show_time(foo)
def foo():#函数上方的@show_time是将其与foo()函数绑定,即将其进行了装饰。
print('hello foo')
time.sleep(3)
return 'finish'
foo()#执行foo()函数,其实是执行被装饰后的wrapper函数,而wrapper函数既有扩展功能,又有被装饰函数的原始功能
#逻辑说明:
@show_time标签加在函数foo()上方,意思是将foo函数作为实参传递给show_time(foo)函数;
show_time函数的返回值是wrapper函数对象,在赋值给foo对象,这样在调用foo()函数时就调用的是wrapper函数对象
#=================== 带定长参数的装饰器 ===================
import time
def show_time(func):
def wrapper(a,b):
start_time=time.time()
ret = func(a,b)
end_time=time.time()
print('spend %s'%(end_time-start_time))
return ret
return wrapper
@show_time #add=show_time(add)
def add(a,b):#与wrapper函数与形参func函数参数一致
time.sleep(1)
print(a+b)
result = add(2,4)
print(result)
#***********************************不定长参数的装饰器**********************************
import time
def show_time(func):
def wrapper(*args,**kwargs):
start_time=time.time()
ret = func(*args,**kwargs)
end_time=time.time()
print('spend %s'%(end_time-start_time))
return ret
return wrapper
@show_time #add=show_time(add)
def add(*args,**kwargs):#与wrapper函数与形参func函数参数一致
print(args)
print(kwargs)
return 'done'
add(2,4,8,9,name='tom')
#*******************************带参数的装饰器*********************************************
import time
def time_logger(flag=0):
def show_time(func):
def wrapper(*args,**kwargs):
start_time=time.time()
ret = func(*args,**kwargs)
end_time=time.time()
print('spend %s'%(end_time-start_time))
return ret
if flag>0:
print('将这个操作的时间记录到日志中')
return wrapper
return show_time
@time_logger(3)
def add(*args,**kwargs):
print(args)
print(kwargs)
return 'done'
add(2,4,8,9,name='tom')
@time_logger(3) 做了两件事:
(1)time_logger(3):得到闭包函数show_time,show_time可操作外部环境变量flag
(2)@show_time :add=show_time(add)
上面的time_logger是允许带参数的装饰器。它实际上是对原有装饰器的一个函数封装,并返回一个装饰器(一个含有参数的闭包函数)。
当我们使用@time_logger(3)调用的时候,Python能够发现这一层的封装,并把参数传递到装饰器的环境中。
#*******************************多层装饰器*********************************************
def makebold(fn):
def wrapper():
return "<b>" + fn() + "</b>"
return wrapper
def makeitalic(fn):
def wrapper():
return "<i>" + fn() + "</i>"
return wrapper
@makebold
@makeitalic
def hello():
return "hello alvin"
ret = hello()
print(ret)#输出<b><i>hello alvin</i></b>
#先执行makeitalic,在执行makebold;装饰器的就近原则
#执行完makeitalic,结果为<i>hello alvin</i>
#执行完makebold,结果为<b><i>hello alvin</i></b>
#详细逻辑见下图