鱼C论坛

 找回密码
 立即注册
查看: 2808|回复: 16

[作品展示] 函数加速引擎——装饰器。

[复制链接]
发表于 2016-10-20 14:05:15 | 显示全部楼层 |阅读模式

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

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

x

Python的很多源码里经常会看到

  1. @abc
  2. def  f():
  3.         return 'fishc'
复制代码

这样的语句。

其中紧跟在@后面的就是装饰器了。

在说装饰器之前,先来看看闭包这个东西。

小甲鱼老师在20讲时说过闭包,课后题传送门。


搞明白这段:
  1. def funOut():
  2.     def funIn():
  3.         print('宾果!你成功访问到我啦!')
  4.     return funIn()
复制代码


怎么访问到 funIn?

答案是:
  1. funOut()
复制代码

------
  1. def funOut():
  2.     def funIn():
  3.         print('宾果!你成功访问到我啦!')
  4.     return funIn
复制代码


怎么访问到 funIn?

答案是:
  1. funOut()()
复制代码


区别在于 funOut后面跟了一个()与两个()。
funOut,funIn是函数
funOut(),funIn()呢,是执行函数

如果你打印funOut你会看到一串内存地址,
funOut()你会看到这个函数执行后的返回值


进阶的需求。
有这么一个函数。

  1. def html_content():

  2.     return 'i love fishc.'
复制代码


这个函数返回 'i love fishc.',
现在我们需要将这串字符串放在p标签, b标签与em标签下组成<p><b><em>i love fishc.</em></b></p>。

很简单嘛,
  1. def html_content():

  2.     return '<p><b><em>i love fishc.</em></b></p>'
复制代码


这时我们又需要将这串字符串放在a标签下组成<a>i love fishc.</a>。

然后我们再次更改html_content函数。

这时又一个人需要把它放在div标签下。

如果我们只有几行代码还很容易修改,当代码多了之后,修改源代码并不划算。

这时候,我们就可以用装饰器来完成这个工作。


  1. def add_em(func1):
  2.     def funin():
  3.         return '<em>{0}</em>'.format(func1())

  4.     return funin
复制代码

我们定义一个叫add_em的新函数。

作用自然是添加一个em标签。

同时我们将原始html_content函数上面放上装饰器。
  1. @add_em
  2. def html_content():

  3.     return 'i love fishc.'

  4. print(html_content())
复制代码


你觉得会出现什么?

没错就是变成这样了。
  1. <em>i love fishc.</em>
复制代码

我们没有修改原始代码就实现了修改原始代码的需求!

原理是什么?

@add_em 相当于 add_em(html_content)

之后我们调用 html_content时,就变成了这样。
html_content()

首先 add_em(html_content) - > funin   函数。
之后 funin + () -> funin()   执行函数。



如法炮制!

  1. def add_em(func1):
  2.     def funin():
  3.         return '<em>{0}</em>'.format(func1())

  4.     return funin

  5. def add_b(func1):
  6.     def funin():
  7.         return '<b>{0}</b>'.format(func1())

  8.     return funin

  9. def add_p(func1):
  10.     def funin():
  11.         return '<p>{0}</p>'.format(func1())

  12.     return funin


  13. @add_p
  14. @add_b
  15. @add_em
  16. def html_content():

  17.     return 'i love fishc.'

  18. print(html_content())
复制代码

  1. <p><b><em>i love fishc.</em></b></p>
复制代码

不仅完成了需求,代码也很简洁,还可以重用!


参数!参数!

很多情况下函数都是有参数的,装饰器怎么带参数嘛。
  1. def html_content(arg):

  2.     return 'i love fishc.{0}'.format(arg)
复制代码


只需要将内层函数加上参数就好了。
  1. def add_em(func1):
  2.     def funin(arg):
  3.         return '<em>{0}</em>'.format(func1(arg))

  4.     return funin
复制代码


为什么会是这样?

上面说到 加上装饰器之后其实就是变成
             add_em(html_content)(arg)
对应返回       funin    (arg)

那么就是给内层函数加上参数咯,两个,三个,n个都是这样。


装饰器是否可以被执行?

  1. def add_em(func1):
  2.     def funin(arg):
  3.         def funinin(arg):
  4.             return '<em>{0}</em>'.format(func1(arg))
  5.         return funinin
  6.     return funin

  7. def a(arg):
  8.     return '5'

  9. @add_em(a)
  10. def html_content(arg):
  11.     return 'i love fishc.{0}'.format(arg)
复制代码



我们知道了@add_em就是 add_em(html_content),
那@add_em(a)也就变成了add_em(a)(html_content),

那是否也会向函数一样可以加多个()表示执行?

答案是否定的,会提示语法错误。
  1. @add_em(a)(a)

  2.     @add_em(a)(a)
  3.               ^
  4. SyntaxError: invalid syntax
复制代码




评分

参与人数 3荣誉 +20 鱼币 +20 贡献 +18 收起 理由
SixPy + 5 + 5 + 5 热爱鱼C^_^
冬雪雪冬 + 10 + 10 + 10 感谢楼主无私奉献!
拈花小仙 + 5 + 5 + 3 感谢楼主无私奉献!

查看全部评分

本帖被以下淘专辑推荐:

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

使用道具 举报

发表于 2016-11-4 13:50:26 | 显示全部楼层
学习学习
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2016-11-4 14:01:11 | 显示全部楼层
学习一下
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2016-12-23 17:04:43 | 显示全部楼层
这个厉害
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2016-12-23 22:03:48 | 显示全部楼层
不错
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

头像被屏蔽
发表于 2016-12-23 23:38:26 | 显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2016-12-23 23:56:03 | 显示全部楼层
挺好的额
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2016-12-24 23:32:38 | 显示全部楼层
学习
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2016-12-28 19:12:27 | 显示全部楼层
感谢分享
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2017-2-23 14:46:11 | 显示全部楼层
这个说得很易懂
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2017-3-14 23:57:44 From FishC Mobile | 显示全部楼层
总算大概懂了,快绕懵了,谢谢分享
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2017-3-28 10:33:19 | 显示全部楼层
学习
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2017-3-28 13:27:05 | 显示全部楼层
@add_em 相当于 add_em(html_content)

之后我们调用 html_content时,就变成了这样。
html_content()

首先 add_em(html_content) - > funin   函数。
之后 funin + () -> funin()   执行函数
这一部分是难点 好难理解啊?
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2018-7-22 19:01:59 | 显示全部楼层
很好,多谢
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2018-8-10 10:57:26 | 显示全部楼层
收藏学习
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2018-10-7 00:56:20 | 显示全部楼层
感谢 终于有点懂装饰器了
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2019-2-18 22:08:48 | 显示全部楼层
受教了,写的很清楚
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

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

本版积分规则

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

GMT+8, 2024-5-1 17:46

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

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