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根据文件大小打log日志
Oct 09 Python
python executemany的使用及注意事项
Mar 13 Python
简单易懂的python环境安装教程
Jul 13 Python
Python实现的爬取网易动态评论操作示例
Jun 06 Python
python 读取.csv文件数据到数组(矩阵)的实例讲解
Jun 14 Python
一行代码让 Python 的运行速度提高100倍
Oct 08 Python
Python简单基础小程序的实例代码
Apr 28 Python
如何通过Python实现标签云算法
Jul 02 Python
DJANGO-URL反向解析REVERSE实例讲解
Oct 25 Python
python通过matplotlib生成复合饼图
Feb 06 Python
python小白切忌乱用表达式
May 29 Python
Django 构建模板form表单的两种方法
Jun 14 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
PDO::errorInfo讲解
2019/01/28 PHP
jQuery数组处理代码详解(含实例演示)
2012/02/03 Javascript
离开当前页面前使用js判断条件提示是否要离开页面
2014/05/02 Javascript
jQuery操作JSON的CRUD用法实例
2015/02/25 Javascript
JQuery通过AJAX从后台获取信息显示在表格上并支持行选中
2015/09/15 Javascript
AngularJS中的Directive自定义一个表格
2016/01/25 Javascript
JavaScript 数组some()和filter()的用法及区别
2016/05/20 Javascript
jQuery ajax调用后台aspx后台文件的两种常见方法(不是ashx)
2016/06/28 Javascript
jQuery中show与hide方法用法示例
2016/09/16 Javascript
vue router导航守卫(router.beforeEach())的使用详解
2019/04/19 Javascript
JS获取表格视图所选行号的ids过程解析
2020/02/21 Javascript
vue商城中商品“筛选器”功能的实现代码
2020/07/01 Javascript
JavaScript canvas实现文字时钟
2021/01/10 Javascript
Python多线程、异步+多进程爬虫实现代码
2016/02/17 Python
Python随机数random模块使用指南
2016/09/09 Python
Python实现二维数组输出为图片
2018/04/03 Python
tensorflow 加载部分变量的实例讲解
2018/07/27 Python
python实现二维数组的对角线遍历
2019/03/02 Python
python查询文件夹下excel的sheet名代码实例
2019/04/02 Python
django创建简单的页面响应实例教程
2019/09/06 Python
python re模块匹配贪婪和非贪婪模式详解
2020/02/11 Python
python多项式拟合之np.polyfit 和 np.polyld详解
2020/02/18 Python
CSS3实现超酷的黑猫警长首页
2016/04/26 HTML / CSS
Origins悦木之源英国官网:雅诗兰黛集团高端植物护肤品牌
2017/11/06 全球购物
Cult Gaia官网:美国生活方式品牌
2019/08/16 全球购物
乌克兰机票、铁路和巴士票、酒店搜索、保险:Tickets.ua
2020/01/11 全球购物
荷兰浴室和卫浴网上商店:Badkamerxxl.nl
2020/10/06 全球购物
酒店大堂副理的职责范文
2014/02/13 职场文书
2014全国两会心得体会
2014/03/17 职场文书
乔迁之喜主持词
2014/03/27 职场文书
教师个人师德总结
2015/02/06 职场文书
义诊活动通知
2015/04/24 职场文书
法定代表人资格证明书
2015/06/18 职场文书
六五普法学习心得体会
2016/01/21 职场文书
正能量励志演讲稿三分钟(范文)
2019/07/11 职场文书
Oracle 11g数据库使用expdp每周进行数据备份并上传到备份服务器
2022/06/28 Oracle