博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Python函数之装饰器
阅读量:6335 次
发布时间:2019-06-22

本文共 3713 字,大约阅读时间需要 12 分钟。

          装饰器

一.装饰器的意义

  比如:以下函数是供我们调用的,但是我们需要在每个函数中都添加同一个功能,该如何做到呢?

  对于函数开放封闭原则,我们一般不允许修改。所以我们引入了装饰器:

def outer(func):    def inner():    print("添加在原函数之前")    r = func()    #保留原函数的返回值    print('添加在原函数之后')    return r       #将保留的返回值返回回去  return inner @outer             #等价于f1 = outer(f1)def f1():    print("F1") def f2():    print("F2") def f3():    print("F3")     def f4():    print("F4")     f1()                #执行函数,f1()已经等价于inner()了

二.简单装饰器的流程剖析

 

三.带参数的装饰器

3.1

#一般装饰器,不能装饰有参数的函数def outer(func):  #func为待装饰的函数    def inner():  #从上往下执行,遇到def inner,就将函数扔进内存空间,但不执行        print("执行原函数前添加的部分")        r = func() #接收原函数的返回值        print("执行原函数后添加的部分")        return r   #返回原函数的返回值    return inner  #返回inner给index           @outer             #index = outer(index)def index():    print("非常复杂的功能")    return True      index()

3.2:修改方案:根据参数的个数,我们主要得修改装饰器的内层函数

#如果待包装函数有参数#需要如何修改装饰器呢def outer(func):     def inner(a1, a2):         print("执行原函数前添加的部分")        r = func(a1, a2)        print("执行原函数后添加的部分")        return r      return inner            @outer           def index(a1, a2):    print("非常复杂的功能")    return a1 + a2     @outerdef home(s1, s2):    print("非常复杂的功能")    return "HOME"      ret1 = index(1, 2)  #应用了装饰器之后index变成装饰器的内层函数了               ret2 = home(1, 2)

3.3:但是,如果不同的待装饰函数的参数个数不一致该怎么办呢?

修改方案:使用动态参数,*arg**kwargs扩大接收参数的形式。

def outer(func):     def inner(*arg ,**kwargs):         print("执行原函数前添加的部分")        r = func(*arg ,**kwargs)  #内部让*argj元组或**kwargs字典吐出参数,传入原函数        print("执行原函数后添加的部分")        return r      return inner      @outerdef home(s1):       #一个参数    print("非常复杂的功能")    return "HOME" @outer           def index(a1, a2):  #两个个参数    print("非常复杂的功能")    return "INDEX" @outerdef show(x1, x2, x3):#三个参数    print("非常复杂的功能")    return "SHOW"      ret1 = home(1) ret2 = index(1, 2)           ret3 = show(1, 2, 3)

四.使用多装饰器装饰一个函数

应用场景:例如有100个函数,其中10个函数需要加上一部分功能,

而另外90个函数还需要加上额外得一部分功能,怎么做?

方法一

def outer0(func):     def inner(*arg ,**kwargs):         print("执行原函数前添加的部分")        r = func(*arg ,**kwargs)        print("执行原函数后添加的部分")        return r      return inner      def outer1(func):     def inner(*arg ,**kwargs):         print("执行原函数前添加的部分(额外)")        print("执行原函数前添加的部分")        r = func(*arg ,**kwargs)         print("执行原函数后添加的部分")        return r      return inner           @outer0   #功能1def home(s1):         print("非常复杂的功能")    return "HOME" @outer0  #功能1       def index(a1, a2):    print("非常复杂的功能")    return "INDEX"  @outer1  #功能2def show(x1, x2, x3):    print("非常复杂的功能")    return "SHOW"      ret1 = home(1) ret2 = index(1, 2)           ret3 = show(1, 2, 3)

缺点:装饰器outer2的代码与outer的代码有重复的部分,我们应该

尽量避免重复代码

方法二:改进版

def outer1(func):     def inner(*arg ,**kwargs):         print("执行原函数前添加的部分(1)")        r = func(*arg ,**kwargs)        print("执行原函数前添加的部分(4)")            return r      return inner      def outer0(func):     def inner(*arg ,**kwargs):         print("执行原函数前添加的部分(2)")        r = func(*arg ,**kwargs)         print("执行原函数后添加的部分(3)")        return r      return inner @outer0def home(s1):        print("非常复杂的功能")    return "HOME"     @outer1   #先执行这个函数的装饰功能@outer0   #再执行这个函数的装饰功能def index(a1, a2):     print("非常复杂的功能")    return "INDEX"      ret1 = home(1)ret2 = index(1, 2)

多重装饰器流程分析:(原函数的两次变化)

  没应用装饰器之前,原函数就是原函数

  应用第一个装饰器(outer0))之后,原函数变成了outer0函数的内层函数了,由func保留了原函数

  应用第二个装饰器(outer1)之后,outer0的内层函数也就是此时的原函数传入了第二个装饰器里面

去了,替换成第二个装饰器的内存函数,并有第二个装饰器的参数func保存了原函数。

装饰过程

执行过程

装饰次序

#多层装饰器的流程 #第一个装饰器分别装饰第一层和最后一层 #第二个装饰器分别装饰第二层和倒数第二层 #第三个装饰器分别装饰第三层和倒数第三层 #以此类推,中间放要装饰的函数

 五.装饰器的应用

  单层装饰器:比如京东的网页,在进入我的购物车之前需要登录,这个登录就是一个装饰器

  多层装饰器:对于京东的用户来说,有大家公共的页面,也有对于钻石vip和白金vip不同的

        页面,所以在使用第一层登录装饰器之后,还需要加上额外的用户权限的装饰器

 

 

转载于:https://www.cnblogs.com/Acekr/p/7376444.html

你可能感兴趣的文章
第二十一章流 3用cin输入
查看>>
在workflow中,无法为实例 ID“...”传递接口类型“...”上的事件“...” 问题的解决方法。...
查看>>
获取SQL数据库中的数据库名、所有表名、所有字段名、列描述
查看>>
Orchard 视频资料
查看>>
简述:预处理、编译、汇编、链接
查看>>
调试网页PAIP HTML的调试与分析工具
查看>>
路径工程OpenCV依赖文件路径自动添加方法
查看>>
玩转SSRS第七篇---报表订阅
查看>>
WinCE API
查看>>
SQL语言基础
查看>>
对事件处理的错误使用
查看>>
最大熵模型(二)朗格朗日函数
查看>>
深入了解setInterval方法
查看>>
html img Src base64 图片显示
查看>>
[Spring学习笔记 7 ] Spring中的数据库支持 RowMapper,JdbcDaoSupport 和 事务处理Transaction...
查看>>
FFMPEG中关于ts流的时长估计的实现(转)
查看>>
Java第三次作业
查看>>
【HDOJ 3652】B-number
查看>>
android代码混淆笔记
查看>>
Codeforces Round #423 (Div. 2, rated, based on VK Cup Finals) C. String Reconstruction 并查集
查看>>