装饰器

#*********************************** 闭包 ************************************************
定义:如果在一个函数内又定义一个内部函数,内部函数对外层函数的作用域(但不是在全局作用域)的变量进行引用,那么内部函数就被认为是闭包(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>
#详细逻辑见下图
 

 

posted @ 2022-11-17 22:01  大碗麻辣烫  阅读(56)  评论(0)    收藏  举报