装饰器:
方式一:
使用闭包,传入一个函数变量,在内部函数中调用传入的函数变量,这样,执行闭包返回烦人函数时,就相当于也执行了我们传入的函数,并且我们在定义的闭包中,可以在执行传入函数的前后添加我们自己的代码,比如 打印日志,时间,或者统计一些数据等在不改变原来的代码的前提下,添加了新的功能,也就是完成装饰;
代码:
def test2(func):
def innrt():
# 调用传入的函数对象,并将结果返回
print("这是装饰的函数")
return func()
return innrt
def test1():
print("这是第一个函数")
if __name__ == "__main__" :
t = test2(test1)
t()
执行结果是:
这是装饰的函数
这是第一个函数
理解:
执行test2(test1)时,返回的时innrt的引用,执行t(),也就是执行innrt()这个内部定义的函数,这个函数中执行第一句,打印内容,然后执行传入的函数变量,也即是test1这个函数,也即完成了 装饰
第二版 -- 使用注解
在被装饰函数上面添加@装饰函数名,这样的方式实现,原理就和上面是一样的,但是我们在调用的时候,就直接可以调用被装饰的代码,也就是程序之前写好的代码不需要进行修改,但是只要添加可这样的注解,程序运行时就自动完成了装饰:
def w1(func):
def inner():
print('代码执行前进行装饰')
func()
print("代码执行后进行装饰")
return inner
@w1
def w2():
print("原始需要执行的代码")
if __name__ == "__main__":
w2()
执行结果:
代码执行前进行装饰
原始需要执行的代码
代码执行后进行装饰
引申:
函数可以被一个装饰器装饰,那可不可以被多个装饰器装饰呢,当然是可以的,被装饰之后的函数也是一个函数,这个函数可以被看做一个整体,再被第二个函数装饰,写法上也就是说 函数上面可以写多个@函数名 装饰器,写在最上面的装饰器 是最外层的装饰,装饰的下面被装饰后的函数整体:
#第一个装饰器
def decorator1(func):
def innerFunc():
print("装饰器一======before")
func()
print("装饰器一======after")
#返回的是函数引用,也就是函数对象,加上括号的话是执行函数,这样是不对的
return innerFunc
def decorator2(func):
def innerFunc():
print("装饰器二 --------before")
func()
print("装饰器二 -------after")
return innerFunc
#装饰器函数没有参数,不需要写括号,只需要写装饰器函数的函数名即可
@decorator1
@decorator2
def test():
print("----我们要执行的代码,没被装饰的代码----")
#调用
test()
执行结果:
装饰器一======before
装饰器二 --------before
----我们要执行的代码,没被装饰的代码----
装饰器二 -------after
装饰器一======after
三 通用装饰:
将被调用的函数的参数和返回值 也考虑进去的装饰器就是通用装饰器:
def func(functionName):
def func_in(*args, **kwargs):
print("-----记录日志-----")
ret = functionName(*args, **kwargs)
return ret
return func_in
@func
def test():
print("----test----")
return "haha"
@func
def test2():
print("----test2---")
@func
def test3(a):
print("-----test3--a=%d--"%a)
ret = test()
print("test return value is %s"%ret)
a = test2()
print("test2 return value is %s"%a)
test3(11)
这个通用装饰器和之前的区别就是 ,定义的内部函数接受不定长参数和字典参数,也就是说,被装饰的函数可以是带参数的。并且将被装饰的函数的执行结果返回,注意:python中所有函数都有返回值,如果没有return 语句进行返回,那么返回的就是None。
那既然被装饰的函数可以有参数,那么装饰器是否能有参数,这是可以的,这就是带有参数的装饰器:
def decorator(a, b):
def innerdecorator(func): #这个是之前的装饰器,在外面又包装了一层装饰器
def inner():
print("---记录日志-arg=%s, %s--" % (a, b))
ret = func()
return ret
return inner
return innerdecorator
@decorator("haha", "heihei")
def test():
print("---------test----------")
@decorator("111", "2222")
def test2():
print("test2-----")
#调用
test()
test2()
执行结果:
---记录日志-arg=haha, heihei--
---------test----------
---记录日志-arg=111, 2222--
test2-----