回顾
在Python进阶记录之基础篇(十二)中,我们介绍了高阶函数的基本概念以及Python中的几个常用高阶函数,需要重点掌握map( )函数、reduce( )函数、filter( )函数和sorted( )函数的区别和用法。今天我们讲一下Python中的装饰器。
装饰器的概念与意义
装饰器是Python特有的一大特色,要学习并入门Python,装饰器是一道不得不跨越的坎。装饰器本质上是一个Python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象。
装饰器的创建
我们知道,Python中函数也是一个对象,并且可以被直接赋值给变量,同时通过变量也能调用该函数。
函数
上述代码中,我们将say( )函数赋值给变量f,那么f也是一个函数,并且函数名跟函数功能与say( )函数完全一致。
现在,我们要对say( )函数做一个扩展,例如每次调用print语句前打印当前时间。我们可以直接通过修改say( )函数来实现这一需求。(以下代码中,打印当前时间我们使用了Python中内置的time模块,日后讲解模块时再详细介绍。)
print语句前打印当前时间
以上是通过修改say( )函数的定义来实现需求的,但在项目开发中,尤其是多人协作的大型项目,修改他人定义的函数可能会导致修改错误而影响项目的正常运转。因此,有时我们并不希望修改函数定义,此时装饰器就登场了。
本质上,装饰器就是一个返回函数的高阶函数。下面,我们创建一个打印当前时间的简单的装饰器。
简单装饰器
上述代码中,log( )函数就是一个简单的装饰器。可以看到,它接收一个函数,并且返回值也是函数。装饰器里面的wrapper( )函数是整个装饰器的核心,它返回接收的函数say( )函数,这样我们就可以在say( )函数调用前实现打印当前时间的需求了。
对于装饰器,Python同时支持@语法糖的写法,从而简便了装饰器的使用。
@语法糖使用装饰器
@语法糖的写法就是在@后面跟上装饰器的名称,然后放在要使用装饰器的函数定义上面。此时我们再次调用say( )函数,它就会自动去调用装饰器了。
带参数的装饰器
在上述装饰器中,我们看到,wrapper( )函数的参数格式为(*args, **kwargs),因此,wrapper( )函数可以接收任意参数,即调用装饰器的函数可以使用任意参数。
wrapper()函数接收参数
装饰器本身也支持传入参数,不过要实现装饰器本身传参,装饰器内部就需要编写一个返回装饰器的高阶函数,写出来会更加复杂。
装饰器本身带参数
上述代码中,装饰器本身传入了一个name参数,整个装饰器就变成了3层嵌套。从结构上看,这个装饰器中的wrapper( )函数单独拿出来就是一个不带参数的装饰器。因此,装饰器本身要传参,其实就是在不带参数的装饰器外再加一层嵌套,将要传入的参数传入即可。
总结
以上内容介绍了Python中装饰器的基本概念和用法,需要重点掌握装饰器的创建、传参以及作用,装饰器的作用就是为已经存在的函数或对象添加额外的功能。装饰器在我们使用Python进行项目开发时会大量使用到,尤其是用于有切面需求的场景,比如插入日志、性能测试、缓存等。有了装饰器,我们就可以抽离出大量与函数功能本身无关的雷同代码并继续重用。感谢大家的支持与关注,欢迎一起学习交流~