python装饰器与闭包_python闭包与装饰器

本文针对: 学不会,学过即忘,学完跑路 的相关python人群.

一.Python闭包

定义: 访问了定义体以外的定义的非全局变量.(刚学时看不懂这句话太TM正常了)

定义解析: 其实就是函数里面再定义一个函数,里层函数引用了外层函数的变量,这就是闭包.

ContractedBlock.gif

ExpandedBlockStart.gif

1 defwrapper():2 whatever = 'abandon'

3 definner():4 print(whatever)5 print(inner.__closure__) #闭包: (,)

6

7 wrapper()

最简单闭包形成

这里需要说明的是闭包形成与否和是否返回内存函数并无直接关系,只是这样我们就无法运用闭包了,所以正常情况下必须返回.

二.Python装饰器

1.这玩意有什么用

装饰器,装饰器,自然是装饰东西用的.这里的"东西"即是python中的一等公民--函数.

2.函数为什么需要装饰

这个说起来话就长了,这里长话短说,总结成一句话: 中心思想: 简单省事以及--别动老子代码.

3.装饰器的作用

这里引入一个软件设计的原则:

开放封闭原则--对扩展代码的功能是开放的,但是对修改源代码是封闭的.(即功能你可以加,但是代码您可别动...)

那么python中怎么去实现呢--装饰器啊!

4.装饰器的写法和引用

a.装饰器需要用到闭包;

b.装饰器需要返回内存函数;

c.装饰器使用"@"符号调用;

ex:

ContractedBlock.gif

ExpandedBlockStart.gif

1 def zsq(func): #zsq: decorator的拼音

2 definner():3 print('卧槽!') #加一个热血沸腾的语气词

4 func()5 returninner6

7 @zsq #调用装饰器

8 defhaoyougei():9 print("你不要过来啊!")10

11 @zsq #调用装饰器

12 defaduogeng():13 print("为什么是你!")14

15 @zsq #调用装饰器

16 defaxiba():17 print("居然是你!")18

19 axiba()20 aduogeng()21 haoyougei()22

给函数加个文明的语气词

如上述代码,为了防止定义的函数被再次更改代码(以及简单方便),使用@调用装饰器是事半功倍的方法.

5.装饰器的特性:

a.能把被装饰的函数替换成其他函数;

所以上面代码可以理解为:

axiba = zsq(axiba)

axiba()

aduogeng = zsq(aduogeng)

aduogeng()

haoyougei = zsq(haoyougei)

haoyougei()

b.装饰器函数在加载模块上立即执行,不需要函数调用.(这一点请自行测试)

三.Python装饰器进阶

看了上面的部分后如果了解python函数的你在写代码时就可能发现下面的两个问题:

1.被装饰的函数有传参怎么办?

2.定义的装饰器想传参怎么办?

这里引用一下上面的例子:

① axiba = zsq(axiba)

② axiba()

①里面的执行完成后,axiba为zsq返回的inner,调用axiba()时执行的为inner(),此时内存中func保存为axiba,所以执行func()即为执行axiba();

若axiba有传参,如axiba(*args),则func中参数应该为*args,即func(*args),而func的传参需要从inner中传入,所以写为inner(*args).

所以由上得出, 被装饰的函数有传参时,应该设置在里层函数中,如下:

ContractedBlock.gif

ExpandedBlockStart.gif

1 def zsq(func): #zsq: decorator的拼音

2 def inner(*args, **kwargs): #(*args, **kwargs)表示接受所有传参

3 print('卧槽!') #加一个热血沸腾的语气词

4 func(*args, **kwargs)5 returninner6

7 @zsq #调用装饰器

8 defhaoyougei(name):9 print("你不要过来啊!{}".format(name))10

11 @zsq #调用装饰器

12 defaduogeng(name):13 print("为什么是你!{}".format(name))14

15 @zsq #调用装饰器

16 defaxiba(name):17 print("居然是你!{}".format(name))18

19

20 #axiba = zsq(axiba)

21 axiba('张益达')22 #aduogeng = zsq(aduogeng)

23 aduogeng('律政先锋')24 #haoyougei = zsq(haoyougei)

25 haoyougei('斯内克')

被装饰的函数拥有传参

解决了一个问题,还剩一个问题,其实第二个问题算是功能性问题--为了实现一些功能而出现的,不然一个正常人不会想到给装饰器传什么参数.

怎么解决呢,其实实现起来非常简单,但是原理有一点绕: 想想上面第一个问题的参数是如何加进去的--最里层调用的函数(func)需要传参,则给其所在层的函数(inner)加上了传参.那么当装饰器函数(zsq)需要传参时,我们给其包装一层函数,并在包装函数上设置传参不就可以了.

所以,当定义的装饰器需要传参时,需要在外层再设置一层包装函数,并将包装函数设置好传参,最后将装饰器函数返回.

ContractedBlock.gif

ExpandedBlockStart.gif

1 def decorator(flag=True): #给装饰器设置一个参数: 形成一个开关

2 def zsq(func): #zsq: decorator的拼音

3 def inner(*args, **kwargs): #(*args, **kwargs)表示接受所有传参

4 print('卧槽!') #加一个热血沸腾的语气词

5 if flag: #使用外部flag标签实现逻辑功能

6 func(*args, **kwargs)7 else:8 print('溜了溜了~')9 returninner10 return zsq #返回装饰器,zsq才是真正的装饰器,decorator是其包装

11

12 @decorator() #调用装饰器decorator ***** 调用的是最外层的包装

13 defhaoyougei(name):14 print("你不要过来啊!{}".format(name))15

16 @decorator(flag=False) #调用装饰器decorator ***** 调用的是最外层的包装

17 defaduogeng(name):18 print("为什么是你!{}".format(name))19

20 @decorator() #调用装饰器decorator ***** 调用的是最外层的包装

21 defaxiba(name):22 print("居然是你!{}".format(name))23

24

25 #axiba = zsq(axiba)

26 axiba('张益达')27 #aduogeng = zsq(aduogeng)

28 aduogeng('律政先锋')29 #haoyougei = zsq(haoyougei)

30 haoyougei('斯内克')

装饰器的传参实现

到这里基本上算是将python装饰器的基本概念和实现说明完毕,另提一嘴from functools import wraps,想多了解的话google一下吧.

自己写4到5个装饰器,基本上就初步掌握了.

The End!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值