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. 关于“@”符号
    • @符号作用

      @符号是python中的一个语法糖 为了让装饰语句写起来更加简单代码更加易读。

      在函数定义前一行放置@符号后面接一个装饰器函数名代表该函数被装饰器装饰,相当于在函数定义之后立马执行了一条语句:

      func=decorator(func)

      此处func为被装饰函数,decorator为装饰器函数。

    • @ 符号给初学者带来的障碍

      @符号各种方便但是给初学者理解装饰器带来了一定障碍:初学者很容易忘掉@的实际作用,然后就会想不通装饰器到底是怎么装饰的。

      So 其实这个障碍是我写这篇文章的主要原因。

  5. 装饰器的装饰过程

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

原文地址:https://www.cnblogs.com/RexShao/p/8379189.html

时间: 2024-10-10 22:35:32

python装饰器装饰原理探秘的相关文章

【转】【python】装饰器的原理

写在前面: 在开发OpenStack过程中,经常可以看到代码中的各种注解,自己也去查阅了资料,了解了这是python中的装饰器,因为弱类型的语言可以将函数当成返回值返回,这就是装饰器的原理. 虽然说知道装饰器的使用方法以及原理,但是一直不明白为什么要通过在内部函数返回一个函数名这样的写法,在微信上看到下面这篇文章,豁然开朗.因为觉得写的非常好,所以我也没必要再来写一遍了,直接转载,供以后的开发中参考. -----------------------------------------------

装饰器的原理及其用法

什么是装饰器 装饰器是一个很著名的设计模式,经常被用于有切面需求的场景,较为经典的有插入日志.性能测试.事务处理, Web权限校验, Cache等. 装饰器的作用 很有名的例子,就是咖啡,加糖的咖啡,加牛奶的咖啡. 本质上,还是咖啡,只是在原有的东西上,做了"装饰",使之附加一些功能或特性.例如记录日志,需要对某些函数进行记录,笨的办法,每个函数加入代码,如果代码变了,就悲催了,装饰器的办法,定义一个专门日志记录的装饰器,对需要的函数进行装饰,搞定.装饰器的作用就是为已经存在的对象添加

Python全栈__函数的有用信息、带参数的装饰器、多个装饰器装饰一个函数

1.函数的有用信息 代码1: 1 def login(username, password): 2 """ 3 此函数需要用户名,密码两个参数,完成的是登录的功能. 4 :return: True 登录成功. False登录失败. 5 """ 6 print(login.__name__) 7 print(login.__doc__) 8 print('登录成功...') 9 return True 10 11 print(login.__nam

关于多个装饰器装饰一个函数执行顺序的问题

我们通过两个实例来解开我们的疑惑: 实例一: def war1(func): def inner(*args, **kwargs): print("======war1 start=====") func(*args, **kwargs) print("======war1 end=====") return inner def war2(func): def inner(*args,**kwargs): print("======war2 start==

多个装饰器装饰一个函数

#!/usr/bin/env python # -*- coding:utf-8 -*- # 作者: Apollo # 邮箱: [email protected] # 博客: http://www.zgerji.online/ def wrapper1(func): # func = f def inner1(): print('wrapper1 ,before func') func() print('wrapper1 ,after func') return inner1 def wrapp

day14 带函数的装饰器、多个装饰器装饰一个函数

一.带参数的装饰器:------开关 __author__ = 'Administrator' F=True def outer(F): def wap(fun):#gg def inner(*args,**kwargs): if F: print("inner before") ret=fun(*args,**kwargs)#gg() print("inner after") else: ret=fun(*args,**kwargs) return ret ret

python-day14--带参数的装饰器+多个装饰器装饰同一个函数

1.# 带参数的装饰器def f1(flag): def f2(func): def inner(*args,**kwargs): if flag: '''执行函数之前要做的''' r=func(*args,**kwargs) if flag: '''执行函数之后要做的''' return r return inner return f2@f1(True)def f3(): print('egon') return ('eva')s=f3()print(s) 2.#多个装饰器装饰一个函数 def

22_装饰器、带参数的装饰器、多个装饰器装饰一个函数

一.装饰器的执行流程 1 def wrapper(func): 2 def inner(*args,**kwargs): 3 ret = func(*args,**kwargs) 4 return ret 5 return inner 6 7 @wrapper #fun = wrapper(fun) 8 def fun(s): 9 print('666') 10 return s 11 12 fun('777') 13 print(fun('777')) 14 15 ''' 16 1.程序至上而

Python----多个装饰器装饰一个函数

#装饰器回顾: # def wrapper(f): #f= func1# def inner(*args,**kwargs):# print(333) #1. 333# ret=f(*args,**kwargs)# print(666)# return ret# return inner# @wrapper # func1=wrapper(func1)=inner# def func1(): # inner() 定义函数,将函数加载到内存中,但是不执行,等待被调用# print(111) #2.