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

2024-09-03 19:12

本文主要是介绍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

这篇关于58、Python之函数高级:不定参数的函数,写出更加通用的装饰器的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1133795

相关文章

使用Python实现图像LBP特征提取的操作方法

《使用Python实现图像LBP特征提取的操作方法》LBP特征叫做局部二值模式,常用于纹理特征提取,并在纹理分类中具有较强的区分能力,本文给大家介绍了如何使用Python实现图像LBP特征提取的操作方... 目录一、LBP特征介绍二、LBP特征描述三、一些改进版本的LBP1.圆形LBP算子2.旋转不变的LB

Python中__init__方法使用的深度解析

《Python中__init__方法使用的深度解析》在Python的面向对象编程(OOP)体系中,__init__方法如同建造房屋时的奠基仪式——它定义了对象诞生时的初始状态,下面我们就来深入了解下_... 目录一、__init__的基因图谱二、初始化过程的魔法时刻继承链中的初始化顺序self参数的奥秘默认

Python实现特殊字符判断并去掉非字母和数字的特殊字符

《Python实现特殊字符判断并去掉非字母和数字的特殊字符》在Python中,可以通过多种方法来判断字符串中是否包含非字母、数字的特殊字符,并将这些特殊字符去掉,本文为大家整理了一些常用的,希望对大家... 目录1. 使用正则表达式判断字符串中是否包含特殊字符去掉字符串中的特殊字符2. 使用 str.isa

python中各种常见文件的读写操作与类型转换详细指南

《python中各种常见文件的读写操作与类型转换详细指南》这篇文章主要为大家详细介绍了python中各种常见文件(txt,xls,csv,sql,二进制文件)的读写操作与类型转换,感兴趣的小伙伴可以跟... 目录1.文件txt读写标准用法1.1写入文件1.2读取文件2. 二进制文件读取3. 大文件读取3.1

使用Python实现一个优雅的异步定时器

《使用Python实现一个优雅的异步定时器》在Python中实现定时器功能是一个常见需求,尤其是在需要周期性执行任务的场景下,本文给大家介绍了基于asyncio和threading模块,可扩展的异步定... 目录需求背景代码1. 单例事件循环的实现2. 事件循环的运行与关闭3. 定时器核心逻辑4. 启动与停

基于Python实现读取嵌套压缩包下文件的方法

《基于Python实现读取嵌套压缩包下文件的方法》工作中遇到的问题,需要用Python实现嵌套压缩包下文件读取,本文给大家介绍了详细的解决方法,并有相关的代码示例供大家参考,需要的朋友可以参考下... 目录思路完整代码代码优化思路打开外层zip压缩包并遍历文件:使用with zipfile.ZipFil

Python处理函数调用超时的四种方法

《Python处理函数调用超时的四种方法》在实际开发过程中,我们可能会遇到一些场景,需要对函数的执行时间进行限制,例如,当一个函数执行时间过长时,可能会导致程序卡顿、资源占用过高,因此,在某些情况下,... 目录前言func-timeout1. 安装 func-timeout2. 基本用法自定义进程subp

Python实现word文档内容智能提取以及合成

《Python实现word文档内容智能提取以及合成》这篇文章主要为大家详细介绍了如何使用Python实现从10个左右的docx文档中抽取内容,再调整语言风格后生成新的文档,感兴趣的小伙伴可以了解一下... 目录核心思路技术路径实现步骤阶段一:准备工作阶段二:内容提取 (python 脚本)阶段三:语言风格调

Python结合PyWebView库打造跨平台桌面应用

《Python结合PyWebView库打造跨平台桌面应用》随着Web技术的发展,将HTML/CSS/JavaScript与Python结合构建桌面应用成为可能,本文将系统讲解如何使用PyWebView... 目录一、技术原理与优势分析1.1 架构原理1.2 核心优势二、开发环境搭建2.1 安装依赖2.2 验

Linux内核参数配置与验证详细指南

《Linux内核参数配置与验证详细指南》在Linux系统运维和性能优化中,内核参数(sysctl)的配置至关重要,本文主要来聊聊如何配置与验证这些Linux内核参数,希望对大家有一定的帮助... 目录1. 引言2. 内核参数的作用3. 如何设置内核参数3.1 临时设置(重启失效)3.2 永久设置(重启仍生效