情景介绍
一天,在你正在努力加班的时候,老板给交给你了一个任务,就是在这段代码里将所有函数开始输出一个‘hello’最后输出当前时间,再输出一个“end”,这段代码里包含了大量的函数,你会怎么做?
def f1(): print('proces a') def f2(): print('proces b') def f3(): print('proces c') def f4(): print('proces d') ... ...
刚拿到这个任务,我们可能想着这样做,在每个函数中添加相应的输出语句,这样就能完成任务。
import datetimedef f1(): print('hello') print('proces a') print('datetime.datetime.now()') print('end') def f2(): print('hello') print('proces b') print('datetime.datetime.now()') print('end')def f3(): print('hello') print('proces c') print('datetime.datetime.now()') print('end')def f4(): print('hello') print('proces d') print('datetime.datetime.now()') print('end') ... ...
到我们进行实施的时候我们发现这样写,太麻烦,每一个函数最后都要添加一遍,于是,我们就想到了另一个方法,就是写一个函数,添加在每个函数中。
import datetimedef hel(): print('hello') print(datetime.datetime.now()) print('end')def f1(): print('hello') print('proces a') hel()def f2(): print('hello') print('proces b') hel()def f3(): print('hello') print('proces c') hel()def f4(): print('hello') print('proces d') hel() ... ...
但是我们发现在开始输出的hello还是要添加在每个函数中,这样还是麻烦,为了解决这个问题就要讲讲装饰器了。
装饰器介绍
装饰器本质上是一个Python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象。它经常用于有切面需求的场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等场景。装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离出大量与函数功能本身无关的雷同代码并继续重用。概括的讲,装饰器的作用就是为已经存在的对象添加额外的功能。
简单装饰器
就将开始那个问题来使用装饰器解决一下。
import datetimedef hel(func): def inner(): print('hello') r = func() print(datetime.datetime.now()) print('end') return r return inner @heldef f1(): print('proces a') @heldef f2(): print('proces b') @heldef f3(): print('proces c') @heldef f4(): print('proces d') f1() f2() f3() f4() 执行结果: hello proces a2018-06-24 18:03:21.903651end hello proces b2018-06-24 18:03:21.915651end hello proces c2018-06-24 18:03:21.915651end hello proces d2018-06-24 18:03:21.915651end
是不是使用装饰器相对于之前的写法简单。
针对上面的代码进行解析:
装饰器符号“@”属于语法糖,@修饰符必须出现在函数定义前一行,将下面的函数的名作为参数,不允许和函数定义在同一行。
在上面的代码中,func就是指f1、f2、f3、f4函数,以f1为例,将f1函数作为参数传入hel函数中,在hel函数中再定义一个inner()函数,在inner函数中,首先执行一个print('hello'),在执行f1函数兵将返回值赋值给r,接下来输出时间以及end,最后返回r,inner函数的最后返回inner函数,当我们执行f1函数的时候,就相当于执行了inner函数,并且可以可以拿到f1函数的返回值。
使用装饰器传递参数
上面使用的装饰器中,传入的函数没有带参数,当需要修饰的函数带有参数,我们就在装饰器中的inner函数添加相应的参数,在inner函数里面调用func函数的时候,再次传入。
def hel(func): def inner(name): r = func(name) print('bye') return r return inner @heldef f1(name): print('hello') print(name) name = 'alexsel'f1(name) 输出结果: hello alexsel bye
虽然这样我们就解决了参数的问题,但是我们这次传入的参数仅仅是字符串,如果是更加复杂的参数怎么办,这时候我们可以使用我们之前学习函数时候用到的一些可以接收多种类型的参数,*args,**kwargs,使用这两个参数之后我们可以接收任何类型的参数。
def hel(func): def inner(*args,**kwargs): r = func(*args,**kwargs) print('bye') return r return inner @heldef f1(name): print('hello') print(name) name = 'alexsel'f1(name) 输出结果: hello alexsel bye
到这里,简单的装饰器就讲完了,装饰器还有更高级的用法,下一篇,装饰器二会继续给大家讲解装饰器。