python装饰器装饰原理探秘

Posted rexshao

tags:

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

最近一直没抽出时间来写博客,这篇博客在草稿箱里面躺了好久了,一直都只有一个标题。
现在终于要开始写了。

  1. 为什么要写这个篇文章

    前段时间整天盯着python学习 群,发现好多同学对python很多内容并不是很理解,觉得有必要分享自己这段时间通过学习实践总结出来的一些东西。
    写的过程中我会将一些自己理解的内容直接用文字写出来,感觉没必要去复制粘贴一些概念性的东西,若存在有理解错误的地方,欢迎各位在留言指出一起讨论提高,SO 废话不说开写吧。

  2. 什么是装饰器

    装饰器(Decorator):个人理解装饰器无非就是一个函数,函数的功能是传入一个源函数,丢回来一个包含原函数功能的闭包来替代原函数以供调用。
    哎呀 又扯出一个闭包概念⊙﹏⊙b汗 关于闭包下次有空再写一篇

  3. 装饰器的分类

    以实现一个非常无聊的功能(控制函数运行次数)的装饰器进行举例

    • 不带参数的装饰器

      不带参数的装饰器是真正装的饰器,通过传入一个函数返回一个闭包代替原函数,不带参数的装饰器定义方式如下:

      def my_decorator(func):
          li = list()
          limit = 5
      
          def inner(*args, **kwargs):
              # do some thing
              li.append(1)
              if len(li) > limit:
                  print(‘<%s>只能被调用%s次‘ % (func.__name__, limit))
                  return
              else:
                  return func(*args, **kwargs)
      
          return inner
      
      
      @my_decorator
      def my_func1(n):
          print(‘n is %s‘ % n)
      
      
      def my_func2(n):
          print(‘func2 n is %s‘ % n)
      
      
      for i in range(10):
          my_func1(i)
          my_func2(i)

      执行结果

      n is 0
      func2 n is 0
      n is 1
      func2 n is 1
      n is 2
      func2 n is 2
      n is 3
      func2 n is 3
      n is 4
      func2 n is 4
      <my_func1>只能被调用5次
      func2 n is 5
      <my_func1>只能被调用5次
      func2 n is 6
      <my_func1>只能被调用5次
      func2 n is 7
      <my_func1>只能被调用5次
      func2 n is 8
      <my_func1>只能被调用5次
      func2 n is 9

      通过返回一个inner闭包 实现限制执行次数

    • 带参数的装饰器

      带参数的装饰器函数本身严格意义上并不能算是装饰器,实际上带参数的装饰器函数是一个返回值为装饰器函数的一个函数。
      为什么要有带参数的装饰器?
      就拿前面举的例子来说: 虽然my_decorator实现的功能比较无聊,但是我还是感觉这个无聊的功能不够完美,因为函数执行次数限制在装饰器里面写死了,假如我要限制好几个不同的函数,每个函数限制不同执行次数,那么按照不带参数的装饰器的写法每个限制的执行次数我都要重新写一个装饰器,这显然非常不合理。于是我需要一个带参数的装饰器来实现这种功能。
      下面是实现该功能的函数写法:

      def my_decorator(limit):
      
          def outer(func):
              li = list()
      
              def inner(*args, **kwargs):
                  # do some thing
                  li.append(1)
                  if len(li) > limit:
                      print(‘<%s>只能被调用%s次‘ % (func.__name__, limit))
                      return
                  else:
                      return func(*args, **kwargs)
      
              return inner
          return outer
      
      
      @my_decorator(2)
      def my_func1(n):
          print(‘n is %s‘ % n)
      
      
      @my_decorator(4)
      def my_func2(n):
          print(‘func2 n is %s‘ % n)
      
      
      for i in range(5):
          my_func1(i)
          my_func2(i)

      眼尖的同学可能注意到了这里装饰器装饰写法和不带参数的不同,不带参数时@后面直接接的装饰器函数名此处@后面接了装饰器函数名后还有一对括号和参数
      带了括号和参数意味着函数已经被执行了,相当于@后面跟着的是函数执行的返回值,所以my_decorator函数返回的outer函数闭包才是真正意义上的装饰器函数,
      通过my_decorator的参数limit 我们就可以每次装饰一个函数时都可以指定不同的函数执行次数上限。
      执行结果

      n is 0
      func2 n is 0
      n is 1
      func2 n is 1
      <my_func1>只能被调用2次
      func2 n is 2
      <my_func1>只能被调用2次
      func2 n is 3
      <my_func1>只能被调用2次
      <my_func2>只能被调用4次
  4. 关于“@”符号

  5. 装饰器的装饰过程

    终于写到了正题 ,正题还是以限制














以上是关于python装饰器装饰原理探秘的主要内容,如果未能解决你的问题,请参考以下文章

python装饰器原理及相关操作

Python函数装饰器原理与用法详解《摘》

python中的装饰器原理和作用

Python全栈开发之8装饰器详解

python--装饰器

「低门槛 手把手」python 装饰器(Decorators)原理说明