鱼C论坛

 找回密码
 立即注册
查看: 4071|回复: 5

[技术交流] 深入理解装饰器(二)

[复制链接]
发表于 2018-9-28 20:11:03 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
本帖最后由 RIXO 于 2019-5-9 19:41 编辑

上一篇帖子
深入理解装饰器(一)

在上一篇帖子中,我们已经完成了装饰器的功能,So,现在开始有新的需求了

初级的装饰器虽然可以不修改源代码,添加功能,适用于如何函数,不改变调用方式

但是!!!我们知道函数是有变量的!!!

这样看来,那个装饰器并不能满足 适用于任何函数 这一点需求
如何完美传递函数的参数呢?
再捋一捋思路
@timeit    等价于     func1  =  timeit(func1)
然后调用 func1()     等价于   调用timeit内部的wrapper函数
所以,我直接把参数传递给func1
相当于把参数传递给了wrapper
没错把
重新定义一个func2
  1. def func2(name):
  2.      print('我不是小甲鱼!我是%s'%name)
复制代码

这个函数中我们需要传递一个参数name
所以这样修改装饰器函数
  1. def timeit(every_func):
  2.      def  wrapper(*args,**keywd):
  3.            start = time.clock()
  4.            every_func(*args,**keywd)
  5.            elpase = time.clock() - start
  6.            print(elpase)
  7.      return  wrapper
复制代码


完美,我们已经解决了传入参数的问题了,不管函数需要多少个参数,是什么参数形式,我们都原封不动的再传给了原参数,并添加了计时的功能

但是!!!你会在很多地方发现装饰器的另一种高级写法,那就是向装饰器里面传递参数!!!
@timeit(time = '白天')
这个装饰器只在白天工作,晚上不工作,怎么办呢?(没错,就是这么任性,拒绝加班)
我们再来捋一捋   @timeit   等价于   func2   =   timeit(func2)
@timeit(time = '白天')   等价于啥呢  ?   等价于   func2  =  timeit(time = '白天')
我擦,原函数没有了,那怎么玩,现在func2等价于  timeit函数加入参数执行后的返回值!那么func2这个函数不应该也传进去了吗?装饰器帮我们默认传进了timeit函数的内部函数中
So,现在timeit的函数要变成这样了!

  1. def timeit(time):
  2.      def outwrapper(every_func):
  3.             def  wrapper(*args,**keywd):
  4.                   if  time == '白天':
  5.                         start = time.clock()
  6.                         every_func(*args,**keywd)
  7.                         elpase = time.clock() - start
  8.                         print(elpase)
  9.                   else:
  10.                         print(‘拒绝加班!’)
  11.            return  wrapper
  12.     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,用于执行逻辑,实现功能,调用原函数

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

评分

参与人数 1荣誉 +5 鱼币 +5 贡献 +3 收起 理由
cjjJasonchen + 5 + 5 + 3 感谢楼主无私奉献!

查看全部评分

本帖被以下淘专辑推荐:

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2018-9-29 11:46:12 | 显示全部楼层
-2
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2019-11-27 14:51:44 | 显示全部楼层
写的这么好
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-1-2 19:59:35 | 显示全部楼层
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2023-4-8 22:58:29 | 显示全部楼层
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2023-5-5 21:26:00 | 显示全部楼层
感谢,终于对装饰器有了清晰的认知!
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-5-28 09:33

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表