Python装饰器的简单理解

装饰器本质上是一个Python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象。它经常用于有切面需求的场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等场景。装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离出大量与函数功能本身无关的雷同代码并继续重用。概括的讲,装饰器的作用就是为已经存在的对象添加额外的功能
如下边例子 w1函数是一个闭包这里就是一个装饰函数,为了验证f1函数是否需要被执行 就作为函数innerfunc的参数传入w1 ,执行innerfunc()调用inner函数 验证通过则执行函数func()即 f1()

无参数的函数装饰
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
def w1(func):
def inner():
print("验证权限")
if True:
func()
return inner
def f1():
print("----f1----")
def f2():
print("f2")
innerfunc = w1(f1)
innerfunc()

然后看懂了这个例子就改为装饰器的写法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
def w1(func):
def inner():
print("验证权限")
if True:
func()
return inner
@w1 # @w1 = w1(f1)
def f1():
print("----f1----")
@w1
def f2():
print("----f2----")
f1()
f2()

打印

验证权限 —-f1—-
验证权限 —-f2—-

上边可以看出

1
之前的innerfunc = w1(f1)就换成了 @w1写在f1函数体上边 即为完整的装饰器

这样就实现了不改变f1 或者f2的代码的情况下 给函数增加了其他方法 这里的装饰器比较简单就是 if True: 验证通过即执行函数

再看个简单例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
def makeBlod(fn):
print("函数不执行的时候只要解释器执行@makeBlod就执行此函数了只是暂不调用wrapped函数")
def wrapped():
return "<br>" + fn() + "</br>"
return wrapped
def makeItalic(fn):
def wrapped():
return "<i>" + fn() + "</i>"
return wrapped
#Python解释器执行到这里就开始执行装饰器 而不会等到函数执行的时候再去执行装饰器
@makeBlod
@makeItalic
def test():
return "hello world"
print(test())

输出

1
<br><i>hello world</i></br>

这里注意虽然@makeBlod装饰器先执行但是解释器在往下执行的时候遇到装饰器@makeItalic 就会先等@makeItalic执行wrapped函数完再执行@makeBlod装饰器的wrapped函数

对于有固定参数个数的函数进行装饰
1
2
3
4
5
6
7
8
9
10
11
12
13
14
def func(funcName):
print("---func--1--")
def func_in(a,b):#如果a,b没定义那么会导致test(2,4)调用失败
print("---func_in--1---")
funcName(a,b)#如果a,b没定义那么会导致test(a,b)函数调用失败
print("---func_in--2---")
print("---func--2--")
return func_in
@func
def test(a, b):
print("----test--a=%d,b=%d---"%(a,b))
test(2,4)
对于无固定参数个数的函数进行装饰
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
def func(funcName):
print("---func--1--")
def func_in(*args,**kwargs):
print("---func_in--1---")
funcName(*args,**kwargs)
print("---func_in--2---")
print("---func--2--")
return func_in
@func
def test(a, b ,c):
print("----test--a=%d,b=%d,c=%d---"%(a,b,c))
test(2,4,5)
@func
def test2(a, b, c, d):
print("----test--a=%d,b=%d,c=%d,d=%d---"%(a,b,c,d))
test2(2,4,5,6)
对有返回值的函数进行装饰
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
def func(funcName):
print("---func--1--")
def func_in():
print("---func_in--1---")
returnZhi = funcName()
print(returnZhi)
return returnZhi#带有返回值得函数一定要return此值给源函数
print("---func_in--2---")
print("---func--2--")
return func_in
@func
def test():
print("----test---")
return "haha"
ret = test()
print("test返回值 %s" % ret)

打印

1
2
3
4
5
6
---func--1--
---func--2--
---func_in--1---
----test---
haha
test返回值 haha

通用装饰器适合有无参数有无返回值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
def func(funcName):
print("---func--1--")
def func_in(*args, **kwargs):
print("---func_in--1---")
returnZhi = funcName(*args, **kwargs)
return returnZhi#带有返回值得函数一定要return此值给源函数
print("---func_in--2---")
print("---func--2--")
return func_in
@func
#无参数有返回值
def test():
print("----test---")
return "haha"
ret = test()
print("test返回值 %s" % ret)
#有参数有返回值
@func
def test1(a):
print("----test1=%d---"% a)
return "hahatest1"
ret1 = test1(10)
print("test1返回值 %s" % ret1)
@func
#无参数无返回值
def test2():
print("----test2---")
ret2 = test2()
print("test2返回值 %s" % ret2)
#有参数无返回值
@func
def test3(a):
print("----test3=%d---"%a)
print(test3(3))

打印

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---func--1--
---func--2--
---func_in--1---
----test---
test返回值 haha
---func--1--
---func--2--
---func_in--1---
----test1=10---
test1返回值 hahatest1
---func--1--
---func--2--
---func_in--1---
----test2---
test2返回值 None
---func--1--
---func--2--
---func_in--1---
----test3=3---
None

装饰器带有参数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
def func_arg(arg):
def func(funcName):
def func_in():
if arg == "嘿嘿":
print("嘿嘿记录日志 %s" % arg)
funcName()
else:
print("哈哈记录日志 %s" % arg)
funcName()
return func_in
return func
#先执行func_arg("heihei")函数,返回的是func函数的引用然后就是使用@func就行装饰
@func_arg("哈哈")
#无参数有返回值
def test():
print("----test---")
test()
@func_arg("嘿嘿")
#无参数有返回值
def test2():
print("----test2---")
test2()

打印

1
2
3
4
哈哈记录日志 哈哈
----test---
嘿嘿记录日志 嘿嘿
----test2---

更多理解可以参考http://python.jobbole.com/82344/
https://www.zhihu.com/question/26930016
视频教程链接: https://pan.baidu.com/s/1eR403LK 密码: rmqj