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中实现远程调用(RPC、RMI)简单例子
Apr 28 Python
Python实现购物系统(示例讲解)
Sep 13 Python
用matplotlib画等高线图详解
Dec 14 Python
scrapy spider的几种爬取方式实例代码
Jan 25 Python
python pandas dataframe 按列或者按行合并的方法
Apr 12 Python
python语音识别实践之百度语音API
Aug 30 Python
详解django的serializer序列化model几种方法
Oct 16 Python
python仿抖音表白神器
Apr 08 Python
python 将字符串中的数字相加求和的实现
Jul 18 Python
OpenCV哈里斯(Harris)角点检测的实现
Jan 15 Python
Python模块 _winreg操作注册表
Feb 05 Python
python实现图像高斯金字塔的示例代码
Dec 11 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获取url的函数代码
2011/08/02 PHP
10款PHP开源商城系统汇总介绍
2015/07/23 PHP
Smarty高级应用之缓存操作技巧分析
2016/05/14 PHP
PHP7.1新功能之Nullable Type用法分析
2016/09/26 PHP
laravel 事件/监听器实例代码
2019/04/12 PHP
【消息提示组件】,兼容IE6/7&&FF2
2007/09/04 Javascript
使用dynatrace-ajax跟踪JavaScript的性能
2010/04/12 Javascript
javaScript 动态访问JSon元素示例代码
2013/08/30 Javascript
Jquery对象和Dom对象的区别分析
2014/11/20 Javascript
nodejs URL模块操作URL相关方法介绍
2015/03/03 NodeJs
js实现二级菜单渐隐显示
2015/11/03 Javascript
如何用JavaScript实现动态修改CSS样式表
2016/05/20 Javascript
Node.js实现兼容IE789的文件上传进度条
2016/09/02 Javascript
js实现京东轮播图效果
2017/06/30 Javascript
基于js 字符串indexof与search方法的区别(详解)
2017/12/04 Javascript
Js和VUE实现跑马灯效果
2020/05/25 Javascript
google广告之另类js调用实现代码
2020/08/22 Javascript
Python开发如何在ubuntu 15.10 上配置vim
2016/01/25 Python
python遍历目录的方法小结
2016/04/28 Python
基于DATAFRAME中元素的读取与修改方法
2018/06/08 Python
python学习之hook钩子的原理和使用
2018/10/25 Python
python画图--输出指定像素点的颜色值方法
2019/07/03 Python
Django admin.py 在修改/添加表单界面显示额外字段的方法
2019/08/22 Python
基于python读取.mat文件并取出信息
2019/12/16 Python
解决Python命令行下退格,删除,方向键乱码(亲测有效)
2020/01/16 Python
利用django model save方法对未更改的字段依然进行了保存
2020/03/28 Python
基于opencv的selenium滑动验证码的实现
2020/07/24 Python
加拿大健康、婴儿和美容产品在线购物:Well.ca
2016/11/30 全球购物
LN-CC美国:伦敦时尚生活的缩影
2019/02/19 全球购物
新加坡领先的在线生活方式和杂货购物网站:EAMART
2019/04/02 全球购物
英国领先的互联网葡萄酒礼品商:Vintage Wine & Port
2019/05/24 全球购物
高一生物教学反思
2014/01/17 职场文书
学生干部的自我评价分享
2014/01/18 职场文书
社区母亲节活动方案
2014/03/05 职场文书
同学会邀请函模板
2015/01/30 职场文书
党员年度个人总结
2015/02/14 职场文书