马上注册,结交更多好友,享用更多功能^_^
您需要 登录 才可以下载或查看,没有账号?立即注册
x
本帖最后由 RIXO 于 2019-5-9 19:38 编辑
装饰器是个什么东西呢?通俗点就是一个为了给函数添加功能的函数
实际开发过程中,需求经常有变化,所以我们得不停地改代码添加各种需要
那么有没有一种方法可以实现
1、不修改源代码
2、不修改调用方法
3、完成添加的功能
装饰器就是干这个的!
先从需求来讲,现在有一个函数如下def func1():
print('it's func1 !!!')
为了给函数func1添加一个计时的功能,我们再写个函数
def timeit():
start = time.clock()
func1()
elpase = time.clock() - start
print(elpase)
现在来看,我们为了实现这个功能,付出了什么代价
func1 的源代码没有改变,但是调用的方法改变了,我们需要写timeit() 而不是func1(),而且这个timeit的函数只能运用于func1这个函数,想给其他函数加功能得再重新写
所以,我们想解决通用性问题,可以所有想要这个功能的函数都直接实现,而不用重新写timeit的源代码
因为 函数是一个变量!
所以我们把需要这个功能的函数,当参数传入timeit函数中,实现这个功能def timeit(every_func):
start = time.clock()
every_func()
elpase = time.clock() - start
print(elpase)
timeit(func1) #把func1当作参数传入这个函数
然后再来想如何实现,不改变调用方式呢?
函数是一个变量!!
那么函数名是变量名,值又是什么呢?函数的值实际上就是函数在内存中的地址
so
我们把函数名重新赋值不就解决这个问题了吗?
func1 = timeit(func1)
然后再直接调用
func1()
不好意思,出错了,为什么呢?
因为在这个语句中func1 = timeit(func1),你直接调用了timeit函数 所以这里的赋值 实际上是把 timeit返回值(默认返回值为None)赋值给了func1
而None是不能调用的,所以会出错
快到达目标了,怎么能半途而废呢?所以我们接着改timeit函数def timeit(every_func):
start = time.clock()
return every_func
elpase = time.clock() - start
print(elpase)
我们把timeit函数的返回值设置为传进去的函数内存地址,这样调用的时候,就解决问题了
but!!! return会终止函数,下面的语句就没法执行了,所以,你又没有满足需求
所以再改def timeit(every_func):
def wrapper():
start = time.clock()
every_func()
elpase = time.clock() - start
print(elpase)
return wrapper
这回我们在timeit函数里面又定义了一个函数,作用是什么呢,就是为了在满足需求的情况下,给timeit函数一个可以被调用的返回值(也就是wrapper函数的内存地址)
现在我们再来看看有没有满足需求
func1 = timeit(func1) #把func1函数的内存地址传给timeit函数,然后返回一个内部函数wrapper内存地址赋值给func1
func1() #调用wrapper函数,运行需要添加的功能和调用func1函数
完美,实现了三个功能,实际上一个简单的装饰器已经完成了
不过func1 = timeit(func1)看起来有点辣眼睛,所以我们写一个新的表示方法
@timeit
def func1():
print('it's func1 !!!')
只要在任何函数前面加入@timeit就代表着 func1 = timeit(func1) 这个语句
初级装饰器,完成!下一篇帖子
深入理解装饰器(二)
|