Python 装饰器(decorator)常用的创建方式及解析


Posted in Python onApril 24, 2022

装饰器简介

装饰器(decorator)是一种高级Python语法。可以对一个函数、方法或者类进行加工。在Python中,我们有多种方法对函数和类进行加工,相对于其它方式,装饰器语法简单,代码可读性高。因此,装饰器在Python项目中有广泛的应用。修饰器经常被用于有切面需求的场景,较为经典的有插入日志、性能测试、事务处理, Web权限校验, Cache等。

装饰器的优点是能够抽离出大量函数中与函数功能本身无关的雷同代码并继续重用。即,可以将函数“修饰”为完全不同的行为,可以有效的将业务逻辑正交分解。概括的讲,装饰器的作用就是为已经存在的对象添加额外的功能。例如记录日志,需要对某些函数进行记录。笨的办法,每个函数加入代码,如果代码变了,就悲催了。装饰器的办法,定义一个专门日志记录的装饰器,对需要的函数进行装饰。

基础通用装饰器

源码示例

def wrapper_out(func):
    print('-- wrapper_out start --')

    def inner(*args, **kwargs):
        print("-- inner start --")
        ret = func(*args, **kwargs)
        print("-- inner end --")
        return ret
    print('-- wrapper_out end --')
    return inner
@wrapper_out
def test():
    print("--test--")
    return 1 * 2
if __name__ == '__main__':
    print(">>>>>>>>>>>>>>")
    print(test())

执行结果

-- wrapper_out start --
-- wrapper_out end --
>>>>>>>>>>>>>>
-- inner start --
--test--
-- inner end --
2

带参数装饰器

源码示例

def wrapper_out(mode=None):
    print('-- wrapper_out start --')

    def inner_1(func):
        print("-- inner_1 start --")
        def inner_2(*args, **kwargs):
            print("-- inner_2 start --")
            print(f"mode: {mode}")
            ret = func(*args, **kwargs)
            print("-- inner_2 end --")
            return ret
        print("-- inner_2 end --")
        return inner_2
    print('-- wrapper_out end --')
    return inner_1
@wrapper_out(mode=2)
def test():
    print("--test--")
    return 1 * 2
if __name__ == '__main__':
    print(">>>>>>>>>>>>>>")
    print(test())

源码结果

-- wrapper_out start --
-- wrapper_out end --
-- inner_1 start --
-- inner_2 end --
>>>>>>>>>>>>>>
-- inner_2 start --
mode: 2
--test--
-- inner_2 end --
2

源码解析

带参数的装饰器函数, 需要多嵌套一层, 外层装饰器的参数

预加载的时候已经是根据函数的编写顺序进行加载

执行顺序在对应的最内存函数中调用最外层的装饰器函数参数

被装饰函数是最为 inner_1 的参数进行传入, 被装饰函数的参数是作为 inner_2 的参数传入

被装饰函数的执行位置是在 inner_2 中, 使用inner_1 的参数变量和 inner_2 的参数变量共同协助下进行执行

同时还要使用装饰器函数 wrapper_out 的参数变量进行额外的操作

多装饰器执行顺序

源码示例

def wrapper_out1(func):
    print('-- wrapper_out_1 start --')

    def inner1(*args, **kwargs):
        print("-- inner_1 start --")
        ret = func(*args, **kwargs)
        print("-- inner_1 end --")
        return ret
    print('-- wrapper_out1 end --')
    return inner1
def wrapper_out2(func):
    print('-- wrapper_out_2 start --')
    def inner2(*args, **kwargs):
        print("-- inner_2 start --")
        print("-- inner_2 end --")
    print('-- wrapper_out_2 end --')
    return inner2
@wrapper_out2
@wrapper_out1
def test():
    print("--test--")
    return 1 * 2
if __name__ == '__main__':
    print(">>>>>>>>>>>>>>")
    print(test())

执行结果

-- wrapper_out_1 start --
-- wrapper_out1 end --
-- wrapper_out_2 start --
-- wrapper_out_2 end --
>>>>>>>>>>>>>>
-- inner_2 start --
-- inner_1 start --
--test--
-- inner_1 end --
-- inner_2 end --
2

解析

装饰器的预加载顺序是从上往下, 先将装饰器函数写入内存

装饰器的执行顺序是以最靠近函数体的装饰器开始执行(从内到外)

类装饰器

源码示例

class WrapperOut(object):
    def __init__(self, func):
        print('start init ~~~~~`')
        print('func name is %s ' % func.__name__)
        self.__func = func
        print('end init ~~~~~`')

    def __call__(self, *args, **kwargs):
        print('start test')
        self.__func()
        print('end test')
@WrapperOut
def test():
    print('this is test func')
if __name__ == '__main__':
    print(">>>>>>>>>>>")
    test()

执行结果

start init ~~~~~`
func name is test 
end init ~~~~~`
>>>>>>>>>>>
start test
this is test func
end test

解析

类装饰器是利用了类初始化 init 析构方法来处理 被装饰函数的传入

以及使用 call 方法来满足被装饰函数的执行触发

到此这篇关于Python 装饰器常用的创建方式及解析的文章就介绍到这了!


Tags in this post...

Python 相关文章推荐
python使用wmi模块获取windows下的系统信息 监控系统
Oct 27 Python
详谈Python2.6和Python3.0中对除法操作的异同
Apr 28 Python
python 多维切片之冒号和三个点的用法介绍
Apr 19 Python
tensorflow实现简单逻辑回归
Sep 07 Python
Django框架使用内置方法实现登录功能详解
Jun 12 Python
python获取Pandas列名的几种方法
Aug 07 Python
python web框架Flask实现图形验证码及验证码的动态刷新实例
Oct 14 Python
python常用数据重复项处理方法
Nov 22 Python
Python生成词云的实现代码
Jan 14 Python
Python request post上传文件常见要点
Nov 20 Python
详解Java中一维、二维数组在内存中的结构
Feb 11 Python
python基础学习之生成器与文件系统知识总结
May 25 Python
解决IDEA翻译插件Translation报错更新TTK失败不能使用
python使用BeautifulSoup 解析HTML
Apr 24 #Python
Python中npy和mat文件的保存与读取
Apr 24 #Python
python小型的音频操作库mp3Play
Apr 24 #Python
5个pandas调用函数的方法让数据处理更加灵活自如
Apr 24 #Python
Python 使用 Frame tkraise() 方法在 Tkinter 应用程序中的Frame之间切换
Apr 24 #Python
在 Python 中利用 Pool 进行多线程
Apr 24 #Python
You might like
利用PHP制作简单的内容采集器的代码
2007/11/28 PHP
PHP中使用mktime获取时间戳的一个黑色幽默分析
2012/05/31 PHP
验证控件与Button的OnClientClick事件详细解析
2013/12/04 Javascript
原生JavaScript+LESS实现瀑布流
2014/12/12 Javascript
微信jssdk用法汇总
2016/07/16 Javascript
js仿微信语音播放实现思路
2016/12/12 Javascript
5分钟学会Vue动画效果(小结)
2018/07/21 Javascript
layui select获取自定义属性方法
2018/08/15 Javascript
Jquery获取radio选中值实例总结
2019/01/17 jQuery
Antd下拉选择,自动匹配功能的实现
2020/10/24 Javascript
重命名批处理python脚本
2013/04/05 Python
python多线程编程中的join函数使用心得
2014/09/02 Python
深入理解python中的闭包和装饰器
2016/06/12 Python
Python基于OpenCV实现视频的人脸检测
2018/01/23 Python
一条命令解决mac版本python IDLE不能输入中文问题
2018/05/15 Python
Python Pywavelet 小波阈值实例
2019/01/09 Python
python  文件的基本操作 菜中菜功能的实例代码
2019/07/17 Python
Python中使用gflags实例及原理解析
2019/12/13 Python
Selenium Webdriver元素定位的八种常用方式(小结)
2021/01/13 Python
纯css3使用vw和vh实现自适应的方法
2018/02/09 HTML / CSS
世界第一冲浪品牌:O’Neill
2016/08/30 全球购物
俄罗斯最大的消费电子连锁零售商:Mvideo
2017/06/25 全球购物
中专生学习生活的自我评价分享
2013/10/27 职场文书
自考毕业生自我鉴定
2013/11/04 职场文书
门卫人员岗位职责
2013/12/24 职场文书
可贵的沉默教学反思
2014/02/06 职场文书
文秘大学生求职信
2014/02/25 职场文书
幼儿园父亲节活动方案
2014/03/11 职场文书
员工保密协议书
2014/09/27 职场文书
作文评语集锦
2014/12/25 职场文书
向雷锋同志学习倡议书
2015/04/27 职场文书
2015年公路养护工作总结
2015/05/13 职场文书
2015小学教育教学工作总结
2015/07/21 职场文书
七夕情人节问候语
2015/11/11 职场文书
2016春季小学开学寄语
2015/12/03 职场文书
Win10此设备不支持接收Miracast无法投影的解决方法
2022/07/07 数码科技