闭包和装饰器

Posted kali404

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了闭包和装饰器相关的知识,希望对你有一定的参考价值。

闭包

什么是闭包

内部函数对外部函数作用域里变量的引用(非全局变量),则称内部函数为闭包。

闭包三要素:

     > 1.嵌套函数
  >
  > 2.变量引用(自由变量)
  >
  > 3.返回内部函数

闭包代码I

 def funt1(a, b):
     def funt_in (x):
         return a * x + b
     return funt_in
 ?
 ?
 f = funt1(3, 4)
 print(f(1))  # 1*3+4
 print(f(3))  # 3*3+4
 >>>7
 >>>13

上面的函数中,利用闭包来求一元一次方程的值,更方便,直接输入x的值即可求出对应的y的值。因为这利用了闭包可以记住外部函数的参数的特性。也可以称之为存活状态,可以让外部函数的实参,继续存活在函数体内

闭包代码II

 def count():
     fs = []
     for i in range(1, 4):
         def f():
             return i*i
         fs.append(f)
     return fs
 f1, f2, f3 = count()
 ?
 print(f1())
 print(f2())
 print(f3())
 ?
 >>>9
 >>>9
 >>>9

 

装饰器

什么是装饰器

装饰器其实就是一个闭包,把一个函数当作参数然后返回一个替代版函数。

装饰器有2个特性:

  1、可以把被装饰的函数替换成其他函数

2、可以在加载模块时候立即执行

装饰器对无参数函数进行装饰

 #装饰器本质就是一个闭包,
 #将函数当成参数传进去
 def deco(fun):
     def inner():
         print("你想进行的操作1")
         print("你想进行的操作2")
         fun()
     return inner
 #@deco是一个“语法糖”也是装饰器的写法
 @deco # (test)
 def test():
     print("test函数的操作")
 #这个test已经被装饰了,不是原来的test
 test()
 #14行的test()等同于如下操作:
 #rtn = deco(test)
 #rtn()

执行结果:

 你想执行的操作1
 你想执行的操作2
 teast 函数的操作
 ?

装饰器的功能有:

 >  引入日志
 > 函数的执行时间统计
 > 执行函数前的预备处理
 > 执行函数后的清理功能
 > 权限z校检等场景
 > 缓存

装饰器的分类:

装饰器可分为对有无参数函数进行装饰的装饰器对有无返回值函数进行装饰的装饰器,组合起来一共有4种。即:装饰器对无参数无返回值的函数进行装饰,装饰器对无参数有返回值的函数进行装饰,装饰器对有参数无返回值的函数进行装饰,装饰器对有参数有返回值的函数进行装饰。

下面举一个装饰器实际应用的例子。

无参数函数装饰

 #定义函数:完成包裹数据
 def makeBold(fn):
     def wrapped():
         return "<b>" + fn() + "</b>"
     return wrapped
 ?
 #定义函数:完成包裹数据
 def makeItalic(fn):
     def wrapped():
         return "<i>" + fn() + "</i>"
     return wrapped
 ?
 @makeBold
 def test1():
     return "hello world - 1"
 ?
 @makeItalic
 def test2():
     return "hello world - 2"
 ?
 @makeBold
 @makeItalic
 def test3():
     return "hello world - 3"
 ?
 print(test1())
 print(test2())
 print(test3())

结果:

 <b>hello world - 1</b>
 <i>hello world - 2</i>
 <b><i>hello world - 3</i></b>

上面这个例子是做网页的时候对字体进行设置,对test1()进行加粗,对test2()斜体处理,对test3()先斜体在加粗。注意:对一个函数可以同时使用多个装饰器,装饰顺序由内而外。

对有参数的函数进行装饰

 #定义一个装饰器
 def deco(func):
     def wrapper(a,b):    #内部函数的参数必须和被装饰的函数保持一致
         print("添加的功能")
         func(a,b)
 ?
     return wrapper
 ?
 @deco
 #有参数的函数
 def sum(a,b):
     print(a+b)
 ?
 sum(10,20)

结果为:

 添加的功能
 30
 ?

当装饰器装饰有参数的函数时,装饰器内部的函数有必须带有和其相同的参数,因为被撞的参数的参数会被当成参数传进装饰内部的函数中,如果两者的参数不一致.,会报错.

装饰器对不定长参数的函数进行装饰:

 from time import ctime,sleep
 #定义一个装饰器,装饰不定长参数函数
 def deco(func):
     def wrapper(*args,**kwargs):
         print("%s called at the %s"%(func.__name__,ctime()))
         func(*args,**kwargs)
     return wrapper
 ?
 @deco
 def test1(a,b,c):
     print(a+b+c)
 ?
 @deco
 def test2(a,b):
     print(a+b)
 ?
 test1(10,20,30)
 sleep(2)
 test1(30,40,50)
 ?
 sleep(1)
 test2(10,20)

执行:

 test1 called at the Fri Nov 10 19:08:03 2019
 60
 test1 called at the Fri Nov 10 19:08:05 2019
 120
 test2 called at the Fri Nov 10 19:08:06 2019
 30

装饰器对有返回值的函数进行装饰

 from time import ctime,sleep
 #定义一个装饰器,装饰不定长参数函数
 def deco(func):
     def wrapper(*args,**kwargs):
         print("%s called at the %s"%(func.__name__,ctime()))
         return func(*args,**kwargs)
     return wrapper
 #上面的装饰器是一个万能的装饰器,因为它可以装饰任意一种函数
 #包括有无参数函数和有无返回值函数
 ?
 @deco
 def test():
     return "---ha--ha---"
 ?
 t = test()
 print(t)

执行结果:

  test called at the Fri Nov 10 19:19:20 2019 
 ---ha--ha---

上面的装饰器是一个万能的装饰器,因为其可以用来装饰任何函数,包括有无参数函数和有无返回值函数

以上是关于闭包和装饰器的主要内容,如果未能解决你的问题,请参考以下文章

python函数下篇装饰器和闭包,外加作用域

装饰器和闭包

闭包函数,装饰器

python-闭包和装饰器-02-装饰器(decorator)

python-闭包和装饰器-02-装饰器(decorator)

9.23闭包函数/装饰器/迭代器/生成器