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

南宫理的日志录 2024-10-26 14:10:41
引言

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

本文的主要内容有:

1、简陋装饰器的缺陷

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

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

简陋装饰器的缺陷

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

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

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

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

正常执行结果:

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

执行结果:

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

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

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

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

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

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

再比如:

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

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

直接看代码:

运行结果:

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

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

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

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

直接看代码:

执行结果:

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

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

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

总结

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

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

0 阅读:17

南宫理的日志录

简介:深耕IT科技,探索技术与人文的交集