• 闭包、装饰器


    闭包

    python的装饰器首先要了解闭包是什么?

    • 通常情况下我们定义一个普通函数是这样做的:

      def func():
          print ('哈哈哈')
      • 普通函数的返回值默认为None,也可以自己决定return

    • 闭包函数:

      • 定义:如果在一个内部函数里,对在外部作用域(但不是在全局作用域)的变量进行引用,那么内部函数就被认为是闭包(closure)。

      • 把函数作为返回值返回回来。

      def wai(n):
          def nei():
              sum_num = 0
              for i in range(n):
                  sum_num = sum_num + i
              return sum_num
           return nei
      res = wai(4)
      print(res)
      print(res())
      ​
      <function wai.<locals>.nei at 0x0000016C95E0F6A8>
      6
      • 上面的例子可以看出来wai()函数的返回值是一个求和函数,对res进行调用得到6。

      • 在这个例子中,我们在函数lwai中又定义了函数nei,并且,内部函数nei可以引用外部函数wai的参数和局部变量,当wai返回函数nei时,相关参数和变量都保存在返回的函数中,这种称为“闭包(Closure)”的程序结构拥有极大的威力。

      • 当我们不需要立即得到结果时,可以用闭包的方式保留这个值。

      a = wai(4)
      b = wai(4)
      print(id(a))
      print(id(b))
      ​
      3126981621416
      3126981621552
      • 上面的示例可得a和b两个对象是相互独立的,在内存中有不同的id,所以数据也是独立的。

    装饰器

    • 装饰器是不修改原函数代码,也不修改其他调用该函数的代码的前提下为函数添加新功能。

    • 我的理解:普通闭包是把一般数据类型的变量当做参数传入,而装饰器则是把一个函数当做变量传入,并且在其内部调用该函数之前为其添加新的功能。

    • 看代码:

      def wai(func):
          def nei():
              print('这是函数传入之前的操作')
              func()
              print('这是函数传入之后的操作')
          return nei
      ​
      def func():
          print('我是被装饰的函数')
      ​
      res = wai(func)
      res()
      ​
      这是函数传入之前的操作
      我是被装饰的函数
      这是函数传入之后的操作
      • 例子分析:我们可以看到装饰器的流程是把函数func当做变量传入wai()函数,函数往下走就是调用nei()函数,nei()函数中紧接着又调用func();再看下面调用首先是wai(func),而wai(func)的返回值就是我们闭包里所讲是个函数,即nei函数,所以要看到print结果就要对这个返回值再次调用,把返回值保存成res,对其调用。

      • 从这段代码得出:

        • 1.函数的参数传递的其实是引用,而不是值。

        • 2.函数名也可以是一个变量,所以可以重新赋值。

        • 3.赋值操作的时候,先执行等号右边的。

    • 上面的例子看完我们再看看正经写代码时的规范。也就是用@符号代替了res = wai(func)和res()这两个步骤,方便写代码。我们只需要调用被装饰函数即可。

      def wai(func):
          def nei():
              print('这是函数传入之前的操作')
              func()
              print('这是函数传入之后的操作')
          return nei
      @wai
      def func():
          print('我是被装饰的函数')
          
      func()
      ​
      这是函数传入之前的操作
      我是被装饰的函数
      这是函数传入之后的操作

    装饰器的分类

    • 普通装饰器:即不带任何参数,就是上面的例子。

    • 被装饰函数带参数:

      def wai(func):
          def nei(a):
              print('传入函数之前的操作')
              func(a)
              print('传入函数之后的操作')
          return nei
      @wai
      def func(a):
          print('我是被装饰函数的参数:',a)
      func(2)
      ​
      传入函数之前的操作
      我是被装饰函数的参数: 2
      传入函数之后的操作
    • 装饰器带有参数:

      def head(b):        
          def wai(func):
              def nei(a):
                  print('我是装饰器的参数:',b)
                  print('传入函数之前的操作')
                  func(a)
                  print('传入函数之后的操作')
              return nei
          return wai
      @head(5)
      def func(a):
          print('我是被装饰函数的参数:',a)
      func(2)
      ​
      我是装饰器的参数: 5
      传入函数之前的操作
      我是被装饰函数的参数: 2
      传入函数之后的操作
    • 两个装饰器

      def w1(func):
          print('---正在装饰--')
          def inner():
              print('---正在验证权限1--')
              func()
          return inner
      ​
      ​
      def w2(func):
          print('---正在装饰2--')
          def inner():
              print('---正在验证权限2--')
              func()
          return inner
      ​
      # 只要python解释器执行到了这个代码,那么就会自动的进行装饰,而不是等到调用的时候才装饰的
      @w2
      @w1
      def f1():
          print('---f1')
      ​
      f1()
      ​
      输出结果:
      ---正在装饰--
      ---正在装饰2--
      ---正在验证权限2--
      ---正在验证权限1--
      ---f1

       

  • 相关阅读:
    tomcat配置http、https同时访问
    mycat 多库分表 单库分表(根据uuid)
    分页关联查询时 出现查出数据和条数不匹配 级联查询
    微信公众号转发网页
    maven导出jar包
    sqlserver分割字符
    mysql按字符分割字段排序
    对ajax中数据的得到以及绑定的认识
    对待事情应该有的态度!!!
    对Dom的认识
  • 原文地址:https://www.cnblogs.com/kmnskd/p/9904655.html
Copyright © 2020-2023  润新知