马上注册,结交更多好友,享用更多功能^_^
您需要 登录 才可以下载或查看,没有账号?立即注册
x
本帖最后由 RIXO 于 2019-5-9 19:41 编辑
上一篇帖子
深入理解装饰器(一)
在上一篇帖子中,我们已经完成了装饰器的功能,So,现在开始有新的需求了
初级的装饰器虽然可以不修改源代码,添加功能,适用于如何函数,不改变调用方式
但是!!!我们知道函数是有变量的!!!
这样看来,那个装饰器并不能满足 适用于任何函数 这一点需求
如何完美传递函数的参数呢?
再捋一捋思路
@timeit 等价于 func1 = timeit(func1)
然后调用 func1() 等价于 调用timeit内部的wrapper函数
所以,我直接把参数传递给func1
相当于把参数传递给了wrapper
没错把
重新定义一个func2def func2(name):
print('我不是小甲鱼!我是%s'%name)
这个函数中我们需要传递一个参数name
所以这样修改装饰器函数def timeit(every_func):
def wrapper(*args,**keywd):
start = time.clock()
every_func(*args,**keywd)
elpase = time.clock() - start
print(elpase)
return wrapper
完美,我们已经解决了传入参数的问题了,不管函数需要多少个参数,是什么参数形式,我们都原封不动的再传给了原参数,并添加了计时的功能
但是!!!你会在很多地方发现装饰器的另一种高级写法,那就是向装饰器里面传递参数!!!
@timeit(time = '白天')
这个装饰器只在白天工作,晚上不工作,怎么办呢?(没错,就是这么任性,拒绝加班)
我们再来捋一捋 @timeit 等价于 func2 = timeit(func2)
@timeit(time = '白天') 等价于啥呢 ? 等价于 func2 = timeit(time = '白天')
我擦,原函数没有了,那怎么玩,现在func2等价于 timeit函数加入参数执行后的返回值!那么func2这个函数不应该也传进去了吗?装饰器帮我们默认传进了timeit函数的内部函数中
So,现在timeit的函数要变成这样了!def timeit(time):
def outwrapper(every_func):
def wrapper(*args,**keywd):
if time == '白天':
start = time.clock()
every_func(*args,**keywd)
elpase = time.clock() - start
print(elpase)
else:
print(‘拒绝加班!’)
return wrapper
return outwrapper
完美!我们来捋一捋,我们先把 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,用于执行逻辑,实现功能,调用原函数
完美解决,等以后如果能更好的讲解 高级用法的时候,我再来开个帖子 |