python闭包与装饰器

时间:2020-08-01
本文章向大家介绍python闭包与装饰器,主要包括python闭包与装饰器使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

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

一.Python闭包

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

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

1 def wrapper():
2     whatever = 'abandon'
3     def inner():
4         print(whatever)
5     print(inner.__closure__)    # 闭包: (<cell at 0x000002584285E558: str object at 0x000002584445F230>,)
6 
7 wrapper()
最简单闭包形成

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

二.Python装饰器

  1.这玩意有什么用

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

  2.函数为什么需要装饰

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

  3.装饰器的作用

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

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

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

  4.装饰器的写法和引用

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

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

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

  ex:

 1 def zsq(func):                 # zsq: decorator的拼音
 2     def inner():
 3         print('卧槽!')         # 加一个热血沸腾的语气词
 4         func()
 5     return inner
 6     
 7 @zsq                           # 调用装饰器
 8 def haoyougei():
 9     print("你不要过来啊!")
10 
11 @zsq                           # 调用装饰器
12 def aduogeng():
13     print("为什么是你!")
14 
15 @zsq                           # 调用装饰器
16 def axiba():
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).

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

 1 def zsq(func):                      # zsq: decorator的拼音
 2     def inner(*args, **kwargs):     # (*args, **kwargs)表示接受所有传参
 3         print('卧槽!')              # 加一个热血沸腾的语气词
 4         func(*args, **kwargs)
 5     return inner
 6     
 7 @zsq                                # 调用装饰器
 8 def haoyougei(name):
 9     print("你不要过来啊!{}".format(name))
10 
11 @zsq                                # 调用装饰器
12 def aduogeng(name):
13     print("为什么是你!{}".format(name))
14 
15 @zsq                                # 调用装饰器
16 def axiba(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)需要传参时,我们给其包装一层函数,并在包装函数上设置传参不就可以了.

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

 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         return inner
10     return zsq                          # 返回装饰器,zsq才是真正的装饰器,decorator是其包装
11     
12 @decorator()                                # 调用装饰器decorator ***** 调用的是最外层的包装
13 def haoyougei(name):
14     print("你不要过来啊!{}".format(name))
15 
16 @decorator(flag=False)                      # 调用装饰器decorator ***** 调用的是最外层的包装
17 def aduogeng(name):
18     print("为什么是你!{}".format(name))
19 
20 @decorator()                                # 调用装饰器decorator ***** 调用的是最外层的包装
21 def axiba(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!

 

$flag 上一页 下一页