装饰器函数
装饰器:在函数运行时增加功能且不影响这个函数原有内容
普通装饰器函数
语法:
1 2 3 | @func1 def func2(): pass |
@符号为装饰器函数语法,也常叫做语法糖
先来看一个简单的装饰器函数实现:
1 2 3 4 5 6 7 8 9 10 11 | def wai(func):#装饰器函数,参数部分接收一个函数对象 def nei():#闭包函数 print('this is nei') #要添加的功能 return func()#返回接收到的函数func return nei #返回闭包函数 #在func2()执行的时候,会将func()也执行 def foo(): print('this is foo') foo() |
执行后的结果:
1 2 | this is nei this is foo |
此时的foo函数在原有的基础上,额外多了装饰器函数中的定义的功能
被装饰函数foo在调用时,其实本质上是在进行 wai(foo)()
- wai(foo)()过程解析:
- 装饰器函数wai接收被装饰函数foo作为参数
- 返回return nei,闭包函数nei被返回
- nei()函数调用
- 由于nei函数的返回值为return func(),所以在内函数调用结束时,被装饰函数也会被调用
被装饰函数在调用时,被调用的函数有三个:
wai() nei() 以及 被装饰函数 func()
接下来,让我们充满动力的继续看这样一个例子
被装饰的函数带有参数
我们考虑到,之前的普通装饰器并不能解决;被装饰函数带有参数的问题,如果有这样一个函数
1 2 | def foo(a,b): print(a+b) |
这个函数在定义时,明确两个参数,并且做相加打印的操作
我们有一个胆大的想法,在这个两值相加函数运行后的结果,分别给 a和 b两值多100,但是不修改这个原有 foo函数
1 2 3 4 5 6 7 8 9 10 11 | def wai(func):#装饰器函数 def nei(a,b): #内部闭包函数,在这里的a,b其实也就是我们被装饰函数传入的参数a,b a = a + 100 #在这里,为两个参数分别+100 b = b + 100 #我们还可以在装饰器函数中修改传递函数中变量的值 return func(a,b) return nei @wai def foo(a,b): print(a+b) foo(3,5) |
按照惯有思维,3+5的结果应该是8,但是由于该函数被装饰,我们来看下结果吧:
1
| 30
|
执行后的结果,并不是本身的3+5
装饰器函数内部的闭包函数参数部分接收到了被装饰函数传入的参数,并且在其内部进行了值的修改
最后在闭包函数的返回值处,将修改后的函数传入到return func(a,b),此时被装饰函数调用,但是传入的参数已经不再是之前的3和5了
装饰器函数带有参数
最后,让我们看一下装饰器函数的终极套路
如果我们装饰器函数需要参数怎么办?
你会发现,此时wai函数和nei函数的参数部分都有了自己的意义,那么这个装饰器函数的参数该怎么接收?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | def arg_func(choice='Man'): #我们额外包装一层函数用来接收装饰器函数的参数 def wai(func): #装饰器函数 def nei(name): #闭包函数 print('你好:',name) if choice == 'Man': #如果装饰器函数接收到的参数值为Man print('去工作') if choice == 'Woman': print('去逛街') return func(name) #闭包函数返回被装饰函数调用 return nei #装饰器函数返回内部闭包函数 return wai #最外层函数返回装饰器函数 choice = input('请输入你的性别:') name = input('请输入你的名字:') def func(name): print("你的名字是:",name) func(name) |
执行的效果
1 2 3 4 5 | 请输入你的性别:Man 请输入你的名字:张三 你好: 张三 去工作 你的名字是: 张三 |
1 2 3 4 5 | 请输入你的性别:Woman 请输入你的名字:李四 你好: 李四 去逛街 你的名字是: 李四 |
总结
实现装饰器
- 定义闭包函数
- 闭包函数返回装饰器函数接收参数调用
- 装饰器函数参数部分接收被装饰函数对象
- 闭包函数参数部分接收被装饰函数参数部分
- 如果需要装饰器函数带参数,在最外层在包裹一层函数,形参部分接收装饰器函数参数,返回装饰器函数即可