Python的装饰器

装饰器是什么?在Python中,装饰器是使用'@'语法糖的修饰函数的语句,一般出现在函数定义的上方。装饰器的作用是增强被修饰函数的功能,譬如给函数增加日志功能等。

如何实现装饰器?有两种实现方式,一是基于闭包实现,闭包的概念参考Python中的闭包 - 掘金 (juejin.cn),而是基于类实现,两种方式中,闭包的方式相对简单,我们重点看下基于闭包的装饰器。

1、无参装饰器

打开Pycharm,我们先实现一个简单的闭包,并定义一个普通函数print_info:

在上面代码中,outer_func中嵌套了inner_func的定义,传递func参数,并返回inner_func引用;inner_func定义中,实现了一行打印,并调用了func。普通函数print_info实现了简单打印,仅作演示用。

通常情况下,我们会使用如下方式来用闭包去管理普通函数:

print_info作为参数,调用outer_func得到p,然后p就相当于print_info了,可以正常调用,运行一下:

但是这种方式比较繁琐,而且不够优雅,需要写很多闭包管理语句,因此Python提供了'@'语法糖:

在被修饰函数上面,使用'@装饰器'修饰被修饰函数,然后直接使用print_info即可:

运行结果与不使用'@'语法时一样,但是后者更加简洁和优雅。

实际上,可以简单理解使用'@'语法后的行为:

ini 复制代码
print_info = outer_func(print_info)

这个时候的print_info被修改了,实际上变成了闭包函数,普通函数可以直接使用。

2、有参装饰器

上节的无参装饰器是最简单的,实际应用中可能会需要使用有参装饰器。举个栗子,软件的日志系统通常会分日志级别,比如"debug"、"info"、"warn"、"error"、"fatal"等,如果我们的需求是,不同函数输出不同的日志级别,这个时候使用无参装饰器就无法完成了,必须使用有参装饰器,将日志级别信息通过装饰器传递过去。

在无参装饰器中,两层嵌套函数即可实现无参装饰器,那要实现有参装饰器需要在两层嵌套函数中再增加一层函数定义,形成三层嵌套函数,具体演示如下:

在outger_func定义之外增加了log函数定义,在log函数中,传递日志级别level,并返回outer_func定义。同时,在inner_func中,把level给打印出来了。好了,使用这个三层嵌套函数形成的闭包来修饰下print_info:

可以看到装饰器可以传递参数了,运行一下:

日志级别被正确传递给闭包了。

同无参装饰器一样,可以简单理解有参装饰器使用'@'语法后的行为:

ini 复制代码
print_info = log('debug')(print_info)

所以'@'后会紧跟闭包定义中最近外层函数的引用,并自动完成上述转换。

3、基于类的装饰器

前两节中的装饰器都是基于闭包的,事实上,闭包很多特性,面向对象中也是具备的,因此基于类也可以实现装饰器。基于类的装饰器没有闭包实现方便,这里不作深入分析,仅作示例:

这里补充下,基于类的装饰器是利用魔术方法__call__,这个方法可以类像函数一样执行,效果如下:

markdown 复制代码
# 拥有__call__方法的类
对象 = 类() # 实例化,调用__init__
对象() # 调用__call__方法

4、结束

实际上,装饰器一般出现在大型项目中,譬如大型框架,小型项目通常可以选用。基于函数(闭包)和基于类均可实现装饰器,推荐闭包模式的装饰器,简单易用。

相关推荐
_.Switch9 分钟前
高级Python自动化运维:容器安全与网络策略的深度解析
运维·网络·python·安全·自动化·devops
测开小菜鸟1 小时前
使用python向钉钉群聊发送消息
java·python·钉钉
萧鼎3 小时前
Python并发编程库:Asyncio的异步编程实战
开发语言·数据库·python·异步
学地理的小胖砸3 小时前
【一些关于Python的信息和帮助】
开发语言·python
疯一样的码农3 小时前
Python 继承、多态、封装、抽象
开发语言·python
Python大数据分析@3 小时前
python操作CSV和excel,如何来做?
开发语言·python·excel
黑叶白树3 小时前
简单的签到程序 python笔记
笔记·python
Shy9604183 小时前
Bert完形填空
python·深度学习·bert
上海_彭彭4 小时前
【提效工具开发】Python功能模块执行和 SQL 执行 需求整理
开发语言·python·sql·测试工具·element
zhongcx014 小时前
使用Python查找大文件的实用脚本
python