zoukankan      html  css  js  c++  java
  • 如何理解Python装饰器?

    作者:python教程
    链接:https://www.zhihu.com/question/26930016/answer/360300235;https://www.zhihu.com/question/26930016
    来源:知乎
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

    装饰器就是把一个猴子,塞入炼丹炉,然后就出来一个还是会吃桃子,但有火眼金睛的猴子;还是原来的猴子,但多了特效技能。

     

    下面我们以下4个方面介绍Python的装饰器:

    1. 什么是装饰器?
    2. 为什么Python要引入装饰器?
    3. 装饰器有利于解决哪些问题?
    4. 装饰器背后的原理是什么?

     

    在回答以上4个问题的过程中,你会学会如何使用装饰器

    开始吧

     

    01 什么是装饰器?

    装饰器可以让一个Python函数拥有原本没有的功能,也就是你可以通过装饰器,让一个平淡无奇的函数变的强大,变的漂亮。

     

    举几个现实中的例子

    1、你一个男的程序员,穿上女装,戴上假发,你就有了女人的外表(穿女装、戴假发的过程就是新的特效,你拥有了女人的外表,你原来的小jj还在,没有消失)

    2、你新买的毛坯房,装修,买家具后变好看了(装修、家具就是新的特效)

    3、孙悟空被放进炼丹炉装饰了一下,出来后,学会了火眼金睛,以前的本领都还在

     

    02 为什么Python要引入装饰器?

    因为引入装饰器会便于开发,便于代码复用,可以把烂泥扶上墙,

    装饰器可以让你一秒变女人且可以保住小JJ,当你某天后悔想重新变回男人,只要脱掉女装和假发即可(如果你变女人的时候,给小JJ做了手术(直接修改函数体的内容),想再变回男人可就痛苦了哦)

     

    03 装饰器有利于解决哪些问题?

    例子1:

    扩展功能

    比如你写了一段代码,当你执行 孙悟空() 就打印出它目前的技能

    # python3支持用中文做函数名,
    # 这里为了方便你理解,就用中文,实际情况为了兼容性,你可别用中文哦
    
    def 孙悟空():
      print('吃桃子')
    孙悟空()
    # 输出:
    # 吃桃子

    现在你希望

    孙悟空这个函数 打印出 ’有火眼金睛了’,该怎么做呢?

    是的,你可以直接在函数里加一段 print('有火眼金睛了')

    但是这样会破坏原来的代码,如果你的代码量很多很多的话,修改起来则是灾难,

    不过别担心,你还可以用装饰器来装饰他,让他在原本基础上,扩展出新的功能

    代码如下

    def 炼丹炉(func): # func就是‘孙悟空’这个函数
      def 变身(*args, **kwargs): #*args, **kwargs就是‘孙悟空’的参数列表,这里的‘孙悟空’函数没有传参数,我们写上也不影响,建议都写上  
          print('有火眼金睛了') # 加特效,增加新功能,比如孙悟空的进了炼丹炉后,有了火眼金睛技能  
          return func(*args, **kwargs) #保留原来的功能,原来孙悟空的技能,如吃桃子
      return 变身 # 炼丹成功,更强大的,有了火眼金睛技能的孙悟空出世
    
    @炼丹炉
    def 孙悟空():
      print('吃桃子')
    
    孙悟空()
    # 输出:
    # 有火眼金睛了
    # 吃桃子
    

    例子2:扩展权限认证

    比如你的代码,默认打开就播放动画片,代码如下

    def play():
      print('开始播放动画片 《喜洋洋和灰太狼》')
    
    play()
    # 输出
    # 开始播放动画片 《喜洋洋和灰太狼》

    但是突然某天,你突然希望只允许1岁到10才可以看这个动画片,不希望程序员大叔看这个动画片怎么办?

    是的,你可以修改这个代码,加上年龄限制,但如果我们用装饰器的话,就更简单了,就可以不用破坏原来的代码,而且方便扩展到其他函数上

     
    userAge = 40
    
    def canYou(func):
      def decorator(*args, **kwargs):
          if userAge > 1 and userAge < 10:
              return func(*args, **kwargs)
          print('你的年龄不符合要求,不能看')
      return decorator
    
    @canYou
    def play():
      print('开始播放动画片 《喜洋洋和灰太狼》')
    
    play()
    # 输出
    # 你的年龄不符合要求,不能看
    # 你可以修改上面的 userAge 为9 试试
    

    你看,是不是很简单,实际情况中,很多时候,你需要对一段代码加上权限认证,加上各种功能;但是又不想,或者不方便破坏原有代码,则可以用装饰器去扩展它

     

    04 装饰器背后的实现原理是什么?

     

    原理 代码逆推后如下

    def 炼丹炉(func): 
      def 变身(*args, **kwargs):  
          print('有火眼金睛了') 
          return func(*args, **kwargs) 
      return 变身 
    
    def 孙悟空():  
      print('吃桃子')
    新_孙悟空 = 炼丹炉(孙悟空) #放入原料,原来的弱小的孙悟空,生成炼丹方案给 新_孙悟空 ,这里也可以把炼丹方案给 原来的‘孙悟空’,为了方便理解,给了新的孙悟空 
    
    新_孙悟空() # 执行炼丹程序,新的孙悟空出世
    

    然后这段代码,写起来有点麻烦,Python官方出了一个快捷代码,也就是语法糖,用了语法糖就变成了下面这样

     
    def 炼丹炉(func): 
      def 变身(*args, **kwargs):  
          print('有火眼金睛了') 
          return func(*args, **kwargs) 
      return 变身 
    
    @炼丹炉  # 把下面的 ‘孙悟空’ 塞进炼丹炉,并把新的孙悟空复制给下面的函数
    def 孙悟空():  
      print('吃桃子')
    
    孙悟空() # 执行炼丹程序,新的孙悟空出世
    

    可以一次性在一个函数上用多个装饰器吗?

    当然可以,下面我们给孙悟空,弄个金箍棒,让他学会72变,学会飞

    def 炼丹炉(func):
      def 变身(*args, **kwargs):
          print('有火眼金睛了')
          return func(*args, **kwargs)
      return 变身
    
    def 龙宫走一趟(func):
      def 你好(*args, **kwargs):
          print('有金箍棒了')
          return func(*args, **kwargs)
      return 你好
    
    def 拜师学艺(func):
      def 师傅(*args, **kwargs):
          print('学会飞、72变了')
          return func(*args, **kwargs)
      return 师傅
    
    @拜师学艺
    @龙宫走一趟
    @炼丹炉  
    def 孙悟空():
      print('吃桃子')
    
    孙悟空()
    # 输出
    # 学会飞、72变了
    # 有金箍棒了
    # 有火眼金睛了
    # 吃桃子
    

    上面代码的等效于 拜师学艺(龙宫走一趟(炼丹炉(孙悟空)))

    代码的执行顺序是 先从内到外

    先执行 炼丹炉,然后是龙宫走一趟,最后是拜师学艺,

  • 相关阅读:
    数字重排
    环游世界
    Hibernate笔记(一)增删改查CRUD
    Sliding Window Algorithm 滑动窗口算法
    纯HTML/CSS/JS实现淘宝、京东两种轮播图
    COA计算机组织与结构笔记
    数据结构与算法笔记:最小生成树Kruskal、Prim算法与JAVA实现
    数据结构与算法笔记:图的基础与JAVA实现
    数据结构与算法:并查集
    JDBC学习笔记
  • 原文地址:https://www.cnblogs.com/qiaoli0726/p/14667412.html
Copyright © 2011-2022 走看看