装饰器:定义一个装饰函数,函数必须返回一个闭包(闭包就是执行时所需要的外部变量+函数对象,关于闭包的具体介绍,可参考https://blog.csdn.net/DansonC/article/details/94824808)函数,并且被装饰的函数会被python自动传递给装饰函数,作为装饰函数的一个参数。
装饰器的具体定义:
1、把要装饰的方法作为输入参数;
2、在函数体内可以进行任意的操作(可以想象其中会有很多应用场景);
3、只要确保最后返回一个可执行的函数即可(可以是原来的输入参数函数,也可以是一个新函数)。
装饰器的分类
装饰器分为无参数decorator和有参数decorator
无参数decorator:生成一个新的装饰器函数
有参数decorator:装饰函数先处理参数,再生成一个新的装饰器函数,然后对函数进行装饰。
使用装饰器,需要在其他函数的上面写个@xxxxx,如下面例子的@timer
举个例子,使用装饰器来计算执行一个函数的耗时:
import time
def timer(func): #装饰函数
def wrapper(*arg,**kw):
time1=time.time()#被装饰函数调用前做的事情
print("******before******")
func(*arg,**kw) #做一次函数调用
time2=time.time()#被装饰函数调用后做的事情
print("******after******")
print("time elapsed:%s" %(time2-time1)) #计算执行被装饰函数的耗时
return wrapper
#闭包:func(闭包变量)+wrapper(函数)
@timer
def a(count): #被装饰函数
print("执行次数:",count)
i =1
while i<count:
i+=1
print("a is over!")
a(100)
装饰器其实就是一个闭包,把一个函数当做参数后返回一个替代版函数。
装饰函数中的闭包函数结构如下:
def wrapper(*arg,**kw):
xxx 干一些事情
func(*arg,**kw) #执行被装饰函数
yyy 干另外一些事情
最后装饰函数返回这个闭包,return wrapper,这样就是一个完整的装饰器
装饰器的规则:
规则1:
函数func上面定义了@xxxx,那么等价于 func = xxxx(func)
规则2:
装饰函数xxxx,必须返回一个闭包(一个内置函数+func)
下面来具体分析一下装饰器整个执行过程
def deco(func):
def _deco():
print ("before myfunc() called.")
func()
print (" after myfunc() called.")
# 不需要返回func,实际上应返回原函数的返回值
return _deco
@deco #myfunc=deco(myfunc)
def myfunc():
print (" myfunc() called.")
return 'ok'
#myfunc=deco(myfunc)—>返回了一个闭包:_deco+myfunc
myfunc() #---->执行闭包函数_deco()
myfunc() #---->执行闭包函数_deco()
执行逻辑:
deco(myfunc)
print (“before myfunc() called.”)
myfunc()
print (" after myfunc() called.")
print (" myfunc() called.")
print (" myfunc() called.")
执行过程解释:
装饰函数deco
被装饰函数myfunc
@deco
def myfunc(): —>myfunc= deco(myfunc)
myfunc = deco(myfunc)干了什么呢?
1 调用了deco(myfunc)
2 返回闭包:_deco+外包变量myfunc
3 闭包赋值给了myfunc
4 提醒myfunc变为了闭包函数对象
myfunc()—>干了什么呢?
1 _deco()执行了
2 print (“before myfunc() called.”)
3 myfunc()
4 print (" after myfunc() called.")
myfunc()—>干了什么呢?
1 _deco()执行了
2 print (“before myfunc() called.”)
3 myfunc()
4 print (" after myfunc() called.")
执行结果:
before myfunc() called.
myfunc() called.
after myfunc() called.
before myfunc() called.
myfunc() called.
after myfunc() called.
被装饰函数带参数
def deco(func):
def _deco(*arg,**kw):
print ("before %s called." %func.__name__)
print(func(*arg,**kw))
print (" after %s called." %func.__name__)
# 不需要返回func,实际上应返回原函数的返回值
return _deco
#闭包:_deco+func
@deco
def myfunc(a,b):
print (" myfunc() called.")
return a+b
myfunc(1,2)
myfunc(3,4)
装饰器带参数
def deco(s):
def __deco(func):
def _deco(*arg,**kw):
print ("before %s called." %func.__name__,s)
print(func(*arg,**kw))
print (" after %s called." %func.__name__,s)
# 不需要返回func,实际上应返回原函数的返回值
return _deco
return __deco
#闭包:_deco+func
@deco("hello")
def myfunc(a,b):
print (" myfunc() called.")
return a+b
myfunc(1,2)
myfunc(3,4)
1)多了一步:deco(“hello”) —>返回了闭包:__deco+s
deco=闭包:__deco+s
2)@deco—>__deco(func)+s—>返回了一个闭包_deco+func+s
后面的过程跟上一步的过程一样。
内置装饰器
Python中内置的装饰器有三个:
staticmethod:定义实例方法为静态方法
classmethod:定义实例方法为类方法
property:对类属性的操作
一个函数可以同时被多个装饰器进行装饰,
同时对一个函数使用多个不同的装饰器进行装饰时,装饰器的顺序是怎样的呢?
@A
@B
@C
def f():
pass
等价于:
f = A(B(C(f)))