RIXO 发表于 2018-9-28 20:11:03

深入理解装饰器(二)

本帖最后由 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,用于执行逻辑,实现功能,调用原函数

完美解决,等以后如果能更好的讲解 高级用法的时候,我再来开个帖子

塔利班 发表于 2018-9-29 11:46:12

-2

四点好 发表于 2019-11-27 14:51:44

写的这么好

呱呱呱i 发表于 2023-1-2 19:59:35

{:10_275:}

match123_xbd 发表于 2023-4-8 22:58:29

{:7_138:}

小李老师_2023 发表于 2023-5-5 21:26:00

感谢,终于对装饰器有了清晰的认知!
页: [1]
查看完整版本: 深入理解装饰器(二)