认识python中的装饰器

    作者:课课家教育更新于: 2019-08-08 15:45:26

    大神带你学编程,欢迎选课

    1.什么是装饰器,Python是一种计算机程序设计语言。是一种面向对象的动态类型语言,最初被设计用于编写自动化脚本(shell),随着版本的不断更新和语言新功能的添加,越来越多被用于独立的、大型项目的开发

      装饰器(Decorators)是 Python 的一个重要部分。装饰器本质是函数(具有特定功能的函数),装饰器的功能就是装饰其他函数,也就是为其他函数添加一些附属功能。

    2.装饰器原则

      a.不能修改被装饰函数的源代码。

      b.不能修改被装饰函数的调用方式。(装饰器对于被装饰函数来说是透明的)

    3.预备知识:

      a.函数即“变量”。

      b.高阶函数

        (1)把一个函数名当做实参传递给另一个函数

        (2)返回值中包含函数名。

      c.嵌套函数

      装饰器=高阶函数+嵌套函数

    4.实例

      假设我们现在有两个函数。

    def a():        
    print("aaa")
    def b():
    print("bbb")
    a()
    b()

    输出结果分别是aaa和bbb          

      如果我们要给两个函数添加打印日志的功能该怎么做呢?可以是下面这种做法。
      def a():
         print("aaa")
         print("打印日志")
      def b():
       print("bbb")
       print("打印日志")
      执行结果为:
      aaa   打印日志   bbb   打印日志

      但是在实际的生产环境中,a和b函数正在运行一些功能,那我们如何通过不修改其源代码的情况下给它增加打印日志的功能呢?
      我们可以通过高阶函数来对其进行装饰。
      
       def decorators(func):
          func()
          print("打印日志")
          return func
       def a():
          print("aaa")
       def b():
          print("bbb")
      a = decorators(a)
      b = decorators(b)
      a()

      b()
      如上,我们可以通过高阶函数来对其进行装饰,但是有点小问题,它的运行结果并不是我们想要的。其运行结果如下;
      aaa   打印日志   bbb   打印日志   aaa   bbb
      

      因为函数装饰器由高阶函数和嵌套函数组成,所以我们可以对如上代码进行一定的修改。
    def decorators(func):
    def decorators_():
    func()
    print("打印日志")
    return decorators_
    def a():
    print("aaa")
    def b():
    print("bbb")
    a = decorators(a)
    b = decorators(b)
    a()
    b()
    如上我们在decorators函数中嵌套了一个函数,嵌套的函数来执行装饰效果。执行结果如下:
    aaa 打印日志 bbb 打印日志


      如上代码实现了简单的装饰器的效果。但是在调用执行的时候,需要先调用装饰器,然后将装饰器执行的结果返回来,再调用执行。这样显得很是麻烦。
    python中提供了“@语法糖”,可以让我们省略装饰器返回的执行结果的重新赋值。也就是可以省略如上代码中的a = decorators(a)和b = decorators(b)。代码如下
    def decorators(func):
    def decorators_():
    func()
    print("打印日志")
    return decorators_
    @decorators
    def a():
    print("aaa")
    @decorators
    def b():
    print("bbb")
    a()
    b()
    上述代码的执行结果如下:
    aaa 打印日志 bbb 打印日志

    但是有时候我们的函数是有参数的,因为@decorators,本质上等于a = decorators_(a),所以我们在传参数的时候,只需要将参数传递给decorators_这个函数就行。修改后代码如下:

    def decorators(func):
    def decorators_(*args,**kwargs):
    func(*args,**kwargs)
    print("打印日志")
    return decorators_
    @decorators
    def a(parameter_1,parameter_2):
    print("aaa",parameter_1,parameter_2)
    @decorators
    def b(parameter_1,parameter_2):
    print("bbb",parameter_1,parameter_2)
    a("aaa",3333)
    b("bbb",4444)
    如上,运行结果为:

      aaa aaa 3333
      打印日志
      bbb bbb 4444
      打印日志

    如上,我们便完成了基本的装饰器。

    装饰器的工作原理:以上述代码为例,首先查看我们的decorators函数,它接受一个参数,也就是函数名,在decorators内部又嵌套了一个函数decorators_,该函数接受由被修饰函数传进来的参数,然后再调用被修饰函数,然后再执行打印日志(也就是修饰器的功能),decorators函数的返回值其实就是decorators_。

      再来看我们的被修饰函数,以a()为例,当python解释器遇到@decorators时,就会去调用执行decorators函数,@decorators相当于前面说的a = decorators_(a)。然后经过decorators_的修饰后,decorators的返回值赋值给了a,此时a是已经被修饰过了的,此时的a指向了decorators的内嵌函数decorators_的地址,然后我们再执行a()就是相当于调用的是decorators.decorators_,执行完成后,便完成了对a()函数的修饰。


     

    类装饰器

    class Test(object):
    def __init__(self, func):
    print('test init')
    print('func name is %s ' % func.__name__)
    self.__func = func

    def __call__(self, *args, **kwargs):
    print('打印日志')
    self.__func()
    @Test
    def test():
    print("aaa")
    test()
    执行结果如下:

      test init
      func name is test 
      打印日志
      aaa

课课家教育

未登录