当前位置: 首页 > news >正文

python——装饰器深入研究(一)

在这里插入图片描述

一、装饰器解释

1、装饰器属于设计模式的一种:装饰器模式

2、符合开放封闭原则

开放:对拓展开放
封闭:对修改封闭

3、装饰器用来做什么?

可以在不修改功能函数内部代码的情况下,给功能函数进行拓展新的功能

4、装饰器怎么定义:

1、闭包实现
2、类实现
3、普通函数
只要是可调用的对象(加括号就能调用),都可以作为装饰器,通过callable内置函数进行判断

def runc():
    pass

res=callable(runc)
print(res)

二、采用闭包形式执行

def fun_work(func):

    def fun_test(*args,**kwargs):
        print('开始执行')
        if args[1]==0:
            print('b不能为0')
        else:
            func(*args,**kwargs)
        print('结束执行')
    return fun_test

def work(a, b):
    res = a / b
    print('a除B的结果为:', res)

work=fun_work(work)(10,2)       #todo 执行函数

执行逻辑:

1、将函数work作为参数传递到fun_work函数中,返回fun_test
2、把fun_test返回值用所传参数同名的变量work去接收
3、调用work(),执行fun_test(*args,**kwargs)方法

在这里插入图片描述

三、采用装饰器执行

def fun_work1(func):

    def fun_test1(*args,**kwargs):
        print('开始执行')
        if args[1]==0:
            print('b不能为0')
        else:
            func(*args,**kwargs)
        print('结束执行')
    return fun_test1

@fun_work1
def work(a, b):
    res = a / b
    print('a除B的结果为:', res)

work(10,2)  #todo 执行函数

执行逻辑:

1、@fun_work1 :表示调用装饰器fun_work1函数
2、把被装饰器装饰的函数work传递到fun_work1中
3、并且把返回的结果(fun_test1)传给与函数同名的变量work
4、@fun_work1这行代码相当于work=fun_work1(work)
5、调用work()===执行fun_test1()

在这里插入图片描述

四、闭包实现最简单装饰器的框架

def outer(func):    #func用来接收被装饰器装饰的函数名称

    def inner():
        #函数执行前的功能拓展代码
        func()
        #函数执行后的功能拓展代码

    return inner

@outer
def work():
    pass

work()			#执行work():也就是执行inner()

五、装饰器装饰带有参数的函数

def outer(func):

    def inner(a,b):
        print('a-b的值为:',a - b)
        func(a,b)
        print('a*b的值为:', a * b)
    return inner


@outer
def work(a,b):
    print('a+b的值为:',a + b)

work(10,10)

传参流程图

在这里插入图片描述

六、装饰器如何做到通用,可以装饰参数个数多个的函数?

通用装饰器的写法,一定要会

def outer(func):

    def inner(*args,**kwargs):

        #函数执行前的功能拓展代码
        res=func(*args,**kwargs)
		#函数执行后的功能拓展代码
        return res
    
    return inner


@outer
def work(a,b,c):
    return 'a+b+c的值为:{}'.format(a+b+c)

res=work(10,10,10)
print(res)

七、被装饰器装饰的函数有返回值,怎么解决?

def outer(func):

    def inner(a,b):
        print('a-b的值为:',a-b)
        res=func(a,b)
        print('a*b的值为:', a * b)
        return res
    return inner


@outer
def work(a,b):
    return 'a+b的值为:{}'.format(a+b)

res=work(10,10)
print(res)

八、装饰器装饰类

def decorator(item):            #item接收TestDemo

    def wrapper(*args,**kwargs):

        #功能拓展
        print('{}实例化了一个对象'.format(item))
        result=item(*args,**kwargs)
        #功能拓展

        return result

    return wrapper


@decorator      #TestDemo=decorator(TestDemo)
class TestDemo:
    pass

print(TestDemo)         #<function decorator.<locals>.wrapper at 0x000001E84F9E99D0>

obj=TestDemo()
obj1=TestDemo()
obj2=TestDemo()

print(obj)			#<__main__.TestDemo object at 0x000002826039B0A0>
print(obj1)
print(obj2)

执行逻辑:

1、@decorator:将类TestDemo作为参数传递给装饰器decorator中————————》decorator(TestDemo)
2、并且将decorator(TestDemo)用和传递给装饰器同名的参数TestDemo作为变量——————》TestDemo=decorator(TestDemo)
3、TestDemo():调用TestDemo相当于调用wrapper方法
4、result=item(*args,**kwargs)——————》item表示TestDemo类,初始化一个item对象,result是对象名称
5、调用TestDemo()——————》调用wrapper方法返回result——————》需要接收返回值:obj=TestDemo(),obj就是实例化的对象

九、带参数的装饰器

案例1:用pytest做自动化测试时用到装饰器

@pytest.mark.parametrize('item',[11,22,33,44])
def test_demo(item):
    print("item",item)

@pytest.mark.parametrize('item',[11,22,33,44])的执行逻辑:
先调用函数,将整体的返回值作为装饰器,装饰test_demo函数

@pytest.mark.parametrize('item',[11,22,33,44])
等于
result=pytest.mark.parametrize('item',[11,22,33,44])
@result
执行语句:test_demo=result(test_demo)

案例2:实现带参数的装饰器

def outer(func):

    def inner(*args,**kwargs):

        res=func(*args,**kwargs)

        return res

    return inner


def kobe(age,sex):
    return outer			#必须返回装饰器函数名称

@kobe(18,'aa')
def work():
    print("------------work------------:")


work()

执行逻辑示意图

在这里插入图片描述

缺点:

没办法获得装饰器中的参数age,sex

案例3:实现带参数的装饰器最终版(模板)

最外层的参数,是装饰器的参数
中间层的参数:接收被装饰的函数
最里层的参数:接收的是被装饰器装饰的函数调用时传递的参数

@kobe(18,‘aa’)等同于work=kobe(18,‘aa’)(work)

def kobe(age,sex):
    #todo 最外层的参数,是装饰器的参数
    def outer(func):
        #todo 中间层的参数:接收被装饰的函数
        def inner(*args, **kwargs):
            #todo 最里层的参数:接收的是被装饰器函数调用时传递的参数
            print('装饰器拓展前的功能代码age',age)
            res = func(*args, **kwargs)
            print('装饰器拓展前的功能代码sex', sex)

            return res

        return inner
    return outer

@kobe(18,'aa')
def work():
    print("------------work------------:")


work()

执行结果:

装饰器拓展前的功能代码age 18
------------work------------:
装饰器拓展前的功能代码sex aa
在这里插入图片描述

相关文章:

  • 猿创征文|【C++游戏引擎Easy2D】炫酷动画来这学,位移动画构造函数让节点执行动画
  • 做好规划 拿下未来!
  • MATLAB算法实战应用案例精讲-【智能优化算法】非支配排序遗传算法-NSGA-Ⅱ(附python和matlab代码)
  • 完美免费在线去背景图片,便捷变速。在5秒内消除或者替换图像背景,智能调整颜色,所有操作都在浏览器完成,无需上传图像 - BgSub
  • 一文掌握MySQL的索引(认真排版、简洁易懂)
  • 十、mongodb分片集群运维相关
  • 每日十(?)题之20220903
  • 2.数据结构与算法 进阶知识
  • 下载JDK8 JVM源码
  • 基于某钉探索针对CEF框架的一些逆向思路
  • C++迭代器
  • 关联容器(字典)map
  • 欧拉函数——最大公约数(gcd+筛质数+欧拉函数)
  • 【小程序】网络请求API介绍及网络请求的封装
  • ALTERA FPGA IPCORE核之单口RAM详细教程
  • 「译」Node.js Streams 基础
  • centos安装java运行环境jdk+tomcat
  • CentOS学习笔记 - 12. Nginx搭建Centos7.5远程repo
  • JavaScript 无符号位移运算符 三个大于号 的使用方法
  • js面向对象
  • Linux快速配置 VIM 实现语法高亮 补全 缩进等功能
  • Making An Indicator With Pure CSS
  • Python_OOP
  • Shell编程
  • 从@property说起(二)当我们写下@property (nonatomic, weak) id obj时,我们究竟写了什么...
  • 聊聊flink的BlobWriter
  • 码农张的Bug人生 - 见面之礼
  • 使用Swoole加速Laravel(正式环境中)
  • 学习使用ExpressJS 4.0中的新Router
  • 《天龙八部3D》Unity技术方案揭秘
  • 不要一棍子打翻所有黑盒模型,其实可以让它们发挥作用 ...
  • 新海诚画集[秒速5センチメートル:樱花抄·春]
  • ​DB-Engines 12月数据库排名: PostgreSQL有望获得「2020年度数据库」荣誉?
  • (14)目标检测_SSD训练代码基于pytorch搭建代码
  • (C语言)球球大作战
  • (vue)el-checkbox 实现展示区分 label 和 value(展示值与选中获取值需不同)
  • (顶刊)一个基于分类代理模型的超多目标优化算法
  • (二)windows配置JDK环境
  • (附源码)springboot美食分享系统 毕业设计 612231
  • (三分钟了解debug)SLAM研究方向-Debug总结
  • (四)汇编语言——简单程序
  • ./mysql.server: 没有那个文件或目录_Linux下安装MySQL出现“ls: /var/lib/mysql/*.pid: 没有那个文件或目录”...
  • .net core 调用c dll_用C++生成一个简单的DLL文件VS2008
  • .net core 微服务_.NET Core 3.0中用 Code-First 方式创建 gRPC 服务与客户端
  • .NET NPOI导出Excel详解
  • .NetCore部署微服务(二)
  • .net和php怎么连接,php和apache之间如何连接
  • .NET简谈设计模式之(单件模式)
  • @angular/cli项目构建--Dynamic.Form
  • @entity 不限字节长度的类型_一文读懂Redis常见对象类型的底层数据结构
  • [2021 蓝帽杯] One Pointer PHP
  • [Android]Android开发入门之HelloWorld
  • [Android]通过PhoneLookup读取所有电话号码
  • [BZOJ]4817: [Sdoi2017]树点涂色
  • [BZOJ1178][Apio2009]CONVENTION会议中心