58、Python之函数高级:不定参数的函数,写出更加通用的装饰器

引言

上一篇文章中,我们见到引入了Python中的装饰器,通过一个简单的案例实现了一个初步的装饰器,但是,这个装饰器其实是有些缺陷。这一篇文章中,我们对上一篇文章中的装饰器进行一个优化升级,从而写出更加通用的装饰器。

本文的主要内容有:

1、简陋装饰器的缺陷

2、关于函数参数的更加通用的写法

3、更加规范通用的装饰器实现方式

简陋装饰器的缺陷

我们之所以需要使用装饰器,很多时候就是因为需要对很多现有功能,动态添加新的功能,实现更高级别的代码复用。

但是,装饰器是作用于函数的,其增强的目标是函数。但是,根据实际的需要,每个函数的参数及返回值可能是多种多样的。怎么能够写出一个装饰器,能够对各种函数都能进行装饰呢?

首先,回看一下上一篇文章中,关于统一添加登录功能的装饰器的写法:

# 扩展1:新增登录功能
def login(user):print(f"用户[{user}]登录成功")# 扩展2:装饰器:对传入的函数进行登录功能的动态添加
def login_wrap(func):def inner(user):login(user)func(user)return inner@login_wrap
def read(user):print(f"用户[{user}]查看系统相关信息")@login_wrap
def write(user):print(f"用户[{user}]修改系统相关信息")

这个装饰器最大的问题,显然是只能封装只有一个参数而且没有返回值的函数。如果函数有返回值或者函数参数个数不是一个,就会出现问题,比如,尝试通过@login_wrap封装下面这个函数:

def send_msg(from_user, to_user, content):print(f"{from_user}对{to_user}说:{content}")if __name__ == '__main__':send_msg('张三', '李四', '天气真好,万里无云,不远处飘着朵朵白云')

正常执行结果:

a7eb8aeace0e3e69c9270b37cc7e4423.jpeg

如果尝试使用@login_wrap进行封装:

from m1 import login_wrap@login_wrap
def send_msg(from_user, to_user, content):print(f"{from_user}对{to_user}说:{content}")if __name__ == '__main__':send_msg('张三', '李四', '天气真好,万里无云,不远处飘着朵朵白云')

执行结果:

748470e449d45b3f2507e591ebb89194.jpeg

只能接收一个参数,却传入了3个参数。

关于函数参数的更加通用的写法

只要装饰器嵌套的内部函数能够接收任意不定长参数,并且返回任意返回值即可(这里的任意,是指包装函数是什么样,装饰器装饰之后也应当保持一样)。

首先,返回值的通用化处理,是比较简单的,只需要将被包装函数的返回值进行原样返回即可(如果函数没有返回值,实际是返回None)。

由于,返回值的处理比较简单,这里就不进行代码的演示了。

比较头痛的是任意函数参数的实现。其实,我们在Python内置模块的函数定义中,总能看到这种任意函数参数的写法,比如:

d896e42d7ffa390fcf3aeeeeb05c0537.jpeg

再比如:

80e9fd03e15e4766727e0133b5f9befc.jpeg

其实,我们在前面的文章《一颗星,两颗星,满天都是小星星》中,已经介绍过*在函数定义中的写法。

我们可以定义一个这样的函数,然后看下,不同形式的参数传递,这种函数的形参写法是如何接收参数传递的。

直接看代码:

def test_args(*args, **kwargs):print(f"args: {args}")print(f"kwargs: {kwargs}")if __name__ == '__main__':test_args()test_args(1, 2, 3)test_args('张三', to='李四', msg='你好')


运行结果:

b79d42c05f02ec777ebd3bffb21a892c.jpeg

可以看到,一个*的形参args会把所有位置参数接收,以一个元组的形式进行存储;两个*的形参kwargs会把所有关键字参数进行接收,以一个字典的形式进行存储。

只需要通过:def xxxx(*args, **kwargs)这种方式,就可以让函数接收任意参数了。

更加规范通用的装饰器实现方式

任意函数的参数形式以及任意函数返回值都已经可以搞定了,那么我们就可以把前面的装饰器进行调整优化了,让它变得更加通用。

直接看代码:

# 扩展1:新增登录功能
def login(*args, **kwargs):print(f"用户[{args[0]}]登录成功")# 扩展2:装饰器:对传入的函数进行登录功能的动态添加
def login_wrap(func):def inner(*args, **kwargs):login(args[0])return func(*args, **kwargs)return inner@login_wrap
def read(user):print(f"用户[{user}]查看系统相关信息")@login_wrap
def write(user):print(f"用户[{user}]修改系统相关信息")@login_wrap
def send_msg(from_user, to_user, content):print(f"{from_user}对{to_user}说:{content}")if __name__ == '__main__':read('张三')write('李四')send_msg('张三', '李四', '天气真好,万里无云,不远处飘着朵朵白云')

执行结果:

b1cca1a7b2644a7470df3ae2f8277944.jpeg

可以看到,不同形式的参数的函数都可以统一进行装饰器增强了。

需要注意的是,*的使用:

e50ecfc1869ed45890d4f7ccd483062a.jpeg

对*的使用,不清楚的,可以翻一下之前的文章,也可以自行搜索引擎检索。

总结

本文首先说明了之前比较粗糙的装饰器实现的缺陷,由于参数形式、返回值等的写法大大降低了装饰器的通用性的问题;然后,回顾了接收任意参数的函数的定义;最后,基于接收任意参数的函数的写法最终优化了装饰器的实现,从而让装饰器变得更加通用。

感谢您的拨冗阅读,希望对您有所帮助!

9a51ace0fb4eba6c505fd848fa4234e5.jpeg

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/1522865.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

【王树森】RNN模型与NLP应用(5/9):多层RNN、双向RNN、预训练(个人向笔记)

Stacked RNN(多层RNN) 1. 原理 多个全连接层可以堆叠,多个卷积层也可以堆叠。同理:RNN也可以堆叠形成多层RNN。 如下图所示:对于每一个时刻的输出 h t h_t ht​,它既会作为下一个时刻的输入,…

ElasticSearch学习笔记(三)RestClient操作文档、DSL查询文档、搜索结果排序

文章目录 前言5 RestClient操作文档5.4 删除文档5.4 修改文档5.5 批量导入文档 6 DSL查询文档6.1 准备工作6.2 全文检索查询6.3 精准查询6.4 地理坐标查询6.5 复合查询6.5.1 相关性算分6.5.2 布尔查询 7 搜索结果处理7.1 排序7.1.1 普通字段排序7.1.2 地理坐标排序 前言 Elast…

Git 下载安装使用基本教程

一、下载 Git,并安装 Git for Windows, 无脑安装。安装完,鼠标右键,会看到这两个东西。 二、Gitee操作 新建仓库 初始化 readme 文件 点击克隆 复制地址 右键 git clone 第一次会需要你输入账号密码 输入后拉取成功。 把想要上传…

【安全生产】叉车安全带报警器有哪些特点?

叉车安全带报警器是用于防止在叉车发生猛烈碰撞或紧急制动时,司机不与方向盘、挡风玻璃等发生二次碰撞或抛出车外,从而造成的严重伤害的一种叉车安全装置、配件。 很多司机在开叉车时经常有不系安全带的习惯,有很多不负责任的人会认为&#…

PHP一键发起灵活定制多功能投票小程序系统源码

​一键发起,灵活定制 —— 多功能投票小程序 🚀【开篇:告别繁琐,投票新体验】🚀 还在为组织投票活动而头疼不已吗?繁琐的流程、有限的选项、难以统计的结果...这些都将成为过去式!今天&#x…

MyPrint打印设计器(六)svg篇-直线

svg-二阶贝塞尔曲线 介绍一款强大的svg操作库,能够通过简单的代码,实现svg绘制与操纵,实现拖拽等功能 代码仓库 在线体验 代码仓库:github 代码仓库:gitee 实战项目:MyPrint 操作简单,组件丰富…

notepad++将换行替换成空

将多行里的换行置为一行,例如将下面的6行置为3行 crrlH打开替换框, 替换目标为【,\r\n】,替换成空,勾选循环查找和 正则表达式,全部替换即可。 替换后的效果

【AI】Pytorch_模型构建

建议点赞收藏关注!持续更新至pytorch大部分内容更完。 本文已达到10w字,故按模块拆开,详见目录导航。 整体框架如下 数据及预处理 模型及其构建 损失函数及优化器 本节目录 模型线性回归逻辑回归LeNetAlexNet 构建模块组织复杂网络初始化网络…

中国各地级市的海拔标准差

海拔标准差是衡量地理测量准确性的重要指标,它通过计算特定地点的海拔测量值与平均海拔之间的偏差来评估数据的可靠性。较小的标准差意味着测量结果较为一致,而较大的标准差则可能指出数据的波动性或测量误差。 计算方法 海拔标准差的计算遵循以下公式…

【pycharm-乱码】简单记录一下都有哪些涉及编码

控制台 路径:setting-》general-》console setting-》editor-》file encodings 路径:setting-》editor->file and code templates #!/user/bin/env python3 # -*- coding: utf-8 -*-setting->tools->ssh terminal

新款14 英寸和16英寸MacBook Pro开始组装生产

据 DigiTimes 报道,苹果的供应链已于 8 月开始批量生产搭载 M4 Pro 和 M4 Max 芯片的下一代 14 英寸和 16 英寸 MacBook Pro 机型。这意味着笔记本电脑的组装工作很可能已经开始。 此信息与显示行业分析师 Ross Young 的说法相符,他声称下一代 14 英寸和…

Edge资源占用优化:调整浏览器设置与关闭自动更新检查

最近,作者在学习过程中,打开任务管理器的时候注意到,即使没有打开浏览器,edge依然有着内存占用较高的情况: 于是就在网上收集了一些后台调优的方法,如果各位朋友有更多优化浏览器资源占用的方法&#xff0c…

智能优化特征选择|基于鲸鱼WOA优化算法实现的特征选择研究Matlab程序(KNN分类器)

智能优化特征选择|基于鲸鱼WOA优化算法实现的特征选择研究Matlab程序(KNN分类器) 文章目录 一、基本原理原理流程举个例子总结 二、实验结果三、核心代码四、代码获取五、总结 智能优化特征选择|基于鲸鱼WOA优化算法实现的特征选择研究Matlab程序&#x…

【Linux系统】线程的同步 生产消费模型

同步 同步概念 同步:在保证数据安全的前提下,让线程能够按照某种特定的顺序访问临界资源,从而有效避免饥饿问题,叫做同步 竞态条件:因为时序问题,而导致程序异常,我们称之为竞态条件。在线程场…

[OpenCV] 数字图像处理 C++ 学习——13Canny边缘检测 附完整代码

文章目录 前言1.理论基础(1)高斯模糊平滑图像(GaussianBlur)(2)计算图像梯度(Sobel/Scharr)(3)非极大值抑制 (Non-maximum Suppression)(4)双阈值检测 (Double Threshold)(5)边缘跟踪(通过滞后处理) 2.代码实现3.完整代码 前言 Canny 边缘检测(高斯滤波…

django学习入门系列之第十点《django中数据库操作--创建与删除表》

文章目录 django创建与删除表开始创建表创建指令新增表删除表删除列新增列修改报错提示语言总结 往期回顾 django创建与删除表 删除表 创建表 修改表 操作目录 开始创建表 class text_into(models.Model):name models.CharField(max_length32)password models.CharField…

Electron快速上手

什么是Electron 一款应用广泛的跨平台的桌面应用开发框架。Electron的本质是结合了 Chromium 与Node.js。使用HTML、CSS、JS 等Web技术构建桌面应用程序。 .vue,.tsx,.less,.ts也可以使用 Electron 流程模型 主进程是纯node环境,可以访问__dirname,fs模块等&#…

DDD设计方法-3-仓储,封装持久化数据

前情提要:一共包含 如下六篇文章(篇幅精简,快速入门) 1、初识DDD 2、聚合、实体、值对象 3、仓储,封装持久化数据 4、端口和适配器 5、领域事件 6、领域服务,实现约定 DDD设计方法-3-仓储,封装…

绿联充电宝怎么样?深度测评西圣、绿联、倍思磁吸充电宝!

在如今这个电子设备不离手的时代,充电宝成为了我们生活中不可或缺的伙伴。而磁吸充电宝以其便捷的使用方式和时尚的外观,更是受到了众多消费者的青睐,今天,我们将对西圣、绿联、倍思这三个品牌的磁吸充电宝进行深度测评&#xff0…

Three之材质Material

本文目录 前言一、基础材质1.1 特点及属性1.2 代码1.3 效果 二、标准材质2.1 特点及属性2.2 代码及效果 三、深度材质四、法向材质五、朗伯材质六、Phong式材质七、粒子材质八、 着色器材质九、其他材质 前言 Three.js中的材质(Material)是独立于物体顶点…