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 筛选数据集中列中value长度大于20的数据集方法
Jun 14 Python
Python中pandas模块DataFrame创建方法示例
Jun 20 Python
Python3 利用requests 库进行post携带账号密码请求数据的方法
Oct 26 Python
python paramiko利用sftp上传目录到远程的实例
Jan 03 Python
itchat-python搭建微信机器人(附示例)
Jun 11 Python
python增加图像对比度的方法
Jul 12 Python
python 利用已有Ner模型进行数据清洗合并代码
Dec 24 Python
Python阶乘求和的代码详解
Feb 14 Python
Pycharm pyuic5实现将ui文件转为py文件,让UI界面成功显示
Apr 08 Python
Django 解决distinct无法去除重复数据的问题
May 20 Python
python raise的基本使用
Sep 10 Python
8g内存用python读取10文件_面试题-python 如何读取一个大于 10G 的txt文件?
May 28 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中json_decode()和json_encode()的使用方法
2012/06/04 PHP
关于PHP自动判断字符集并转码的详解
2013/06/26 PHP
php基于session实现数据库交互的类实例
2015/08/03 PHP
利用php做服务器和web前端的界面进行交互
2016/10/31 PHP
分享别人写的一个小型js框架
2007/08/13 Javascript
extjs_02_grid显示本地数据、显示跨域数据
2014/06/23 Javascript
基于jquery和svg实现超炫酷的动画特效
2014/12/09 Javascript
jQuery+CSS3实现树叶飘落特效
2015/02/01 Javascript
最简单的JavaScript验证整数、小数、实数、有效位小数正则表达式
2015/04/17 Javascript
jquery中ready()函数执行的时机和window的load事件比较
2015/06/22 Javascript
基于JavaScript实现全屏透明遮罩div层锁屏效果
2016/01/26 Javascript
JavaScript正则替换HTML标签功能示例
2017/03/02 Javascript
vue实现表格增删改查效果的实例代码
2017/07/18 Javascript
判断滚动条滑到底部触发事件(实例讲解)
2017/11/15 Javascript
echarts同一页面中四个图表切换的js数据交互方法示例
2018/07/03 Javascript
详解将微信小程序接口Promise化并使用async函数
2019/08/05 Javascript
layui 上传插件 带预览 非自动上传功能的实例(非常实用)
2019/09/23 Javascript
JavaScript实现网页跨年倒计时
2020/12/02 Javascript
Python selenium文件上传方法汇总
2020/11/19 Python
pycharm远程开发项目的实现步骤
2019/01/20 Python
详解python中的线程与线程池
2019/05/10 Python
python生成器用法实例详解
2019/11/22 Python
TensorBoard 计算图的查看方式
2020/02/15 Python
size?爱尔兰官方网站:英国伦敦的球鞋精品店
2019/03/31 全球购物
中科前程Java笔试题
2016/11/20 面试题
公务员职务工作的自我评价
2013/11/01 职场文书
单位实习证明怎么写
2014/01/17 职场文书
村道德模范事迹材料
2014/08/28 职场文书
2014年团委工作总结
2014/11/13 职场文书
2015年劳动部工作总结
2015/05/23 职场文书
美容院管理规章制度
2015/08/05 职场文书
丧事酒宴答谢词
2015/09/30 职场文书
2016年党建工作简报
2015/11/26 职场文书
幼儿园大班教学反思
2016/03/02 职场文书
Prometheus 监控MySQL使用grafana展示
2021/08/30 MySQL
Python matplotlib多个子图绘制整合
2022/04/13 Python