深入理解装饰器(二)
本帖最后由 RIXO 于 2019-5-9 19:41 编辑上一篇帖子
深入理解装饰器(一)
在上一篇帖子中,我们已经完成了装饰器的功能,So,现在开始有新的需求了
初级的装饰器虽然可以不修改源代码,添加功能,适用于如何函数,不改变调用方式
但是!!!我们知道函数是有变量的!!!
这样看来,那个装饰器并不能满足 适用于任何函数 这一点需求
如何完美传递函数的参数呢?
再捋一捋思路
@timeit 等价于 func1=timeit(func1)
然后调用 func1() 等价于 调用timeit内部的wrapper函数
所以,我直接把参数传递给func1
相当于把参数传递给了wrapper
没错把
重新定义一个func2
def func2(name):
print('我不是小甲鱼!我是%s'%name)
这个函数中我们需要传递一个参数name
所以这样修改装饰器函数
def timeit(every_func):
defwrapper(*args,**keywd):
start = time.clock()
every_func(*args,**keywd)
elpase = time.clock() - start
print(elpase)
returnwrapper
完美,我们已经解决了传入参数的问题了,不管函数需要多少个参数,是什么参数形式,我们都原封不动的再传给了原参数,并添加了计时的功能
但是!!!你会在很多地方发现装饰器的另一种高级写法,那就是向装饰器里面传递参数!!!
@timeit(time = '白天')
这个装饰器只在白天工作,晚上不工作,怎么办呢?(没错,就是这么任性,拒绝加班)
我们再来捋一捋 @timeit 等价于 func2 = timeit(func2)
@timeit(time = '白天') 等价于啥呢? 等价于 func2=timeit(time = '白天')
我擦,原函数没有了,那怎么玩,现在func2等价于timeit函数加入参数执行后的返回值!那么func2这个函数不应该也传进去了吗?装饰器帮我们默认传进了timeit函数的内部函数中
So,现在timeit的函数要变成这样了!
def timeit(time):
def outwrapper(every_func):
defwrapper(*args,**keywd):
iftime == '白天':
start = time.clock()
every_func(*args,**keywd)
elpase = time.clock() - start
print(elpase)
else:
print(‘拒绝加班!’)
returnwrapper
returnoutwrapper
完美!我们来捋一捋,我们先把 time参数传入timeit函数中 然后调用 timeit 函数 该函数返回一个 内部函数 outwrapper的函数内存地址 @timeit(time = '白天')等价于 func2=outwrapper(func2)
现在我们调用func2(name = 'Rixo')
实际上相当于调用outwrapper(func2(name = 'Rixo'))
这个outwrapper函数给了我们一个返回值 是他的内部函数wrapper的内存地址 所以我们相当于调用 函数weapper(name = 'Rixo') 这里为什么要定义两个内部函数的好处出来了,我们把函数,当作一个参数,把函数需要的变量当作一个参数 ,把装饰器需要的变量当作一个参数,不是因为不能一起传,而是为了方便区分是哪一种类型的变量,当然这里讲的比较跳跃,一是我能力不够,二是找不到相关的资料,
接着往下面讲, 我们调用了函数wrapper(name = 'Rixo')实际上是运行了里面附加的功能,和调用函数func2,我在写的时候考虑过,条件判断语句为什么不放在outwrapper函数外面,因为装饰器的写法实际上是有一定规范的,虽然写在外面python也能识别,但是却造成了代码逻辑上的混乱。
第一层函数timeit ,用于包裹 内部实现功能的函数,用于储存装饰器的变量
第二层函数outwrapper,用于 储存函数的名字(也就是原函数的内存地址)
第三层函数wrapper,用于执行逻辑,实现功能,调用原函数
完美解决,等以后如果能更好的讲解 高级用法的时候,我再来开个帖子 -2 写的这么好 {:10_275:} {:7_138:} 感谢,终于对装饰器有了清晰的认知!
页:
[1]