鱼C论坛

 找回密码
 立即注册
查看: 81192|回复: 313

[扩展阅读] Python 函数修饰符(装饰器)的使用

  [复制链接]
发表于 2014-8-19 17:04:42 | 显示全部楼层 |阅读模式

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

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

x
转自:关于Python修饰符学习

注意:由于很多童鞋反馈原文一点都不好理解,小甲鱼负有连带责任……所以,我又重新把内容整理了一遍,增加了一些例子,希望能帮助到大家。

1.  修饰符的来源

借用一个博客上的一段叙述:修饰符是一个很著名的设计模式,经常被用于有切面需求的场景,较为经典的有插入日志、性能测试、事务处理等。

修饰符是解决这类问题的绝佳设计,有了修饰符,我们就可以抽离出大量函数中与函数功能本身无关的雷同代码并继续重用。

概括的讲,修饰符的作用就是为已经存在的对象添加额外的功能。

如下:

  1. import time

  2. def timeslong(func):
  3.     start = time.time()
  4.     print("It's time starting ! ")
  5.     func()
  6.     print("It's time ending ! ")
  7.     end = time.time()
  8.     return "It's used : %s." % (end - start)

  9. def myfunc():
  10.     print("Hello FishC.")

  11. t = timeslong(myfunc)
  12. print(t)
复制代码

实现结果:

  1. It's time starting !
  2. Hello FishC.
  3. It's time ending !
  4. It's used : 0.02497720718383789.
复制代码

上面的程序中,定义了一个函数(timeslong()),对一个对象(代码中是 myfunc())的运行时间进行计算。

通常情况下,如果我们需要计算另外一个函数的运算时间,那么我们就需要修改 timeslong() 函数在调用时候的实参。

比如我需要统计 myfunc2 这个函数的运行时间,就需要调用 timeslong(myfunc2) 酱紫。

那么为了优化这种操作,Python 便提出了修饰符这个概念。

我们看下它是怎么实现的:

  1. import time

  2. def timeslong(func):
  3.     def call():
  4.         start = time.time()
  5.         print("It's time starting ! ")
  6.         func()
  7.         print("It's time ending ! ")
  8.         end = time.time()
  9.         return "It's used : %s." % (end - start)
  10.     return call

  11. @timeslong
  12. def myfunc():
  13.     print("Hello FishC.")

  14. print(myfunc())
复制代码

实现的结果是一样的:

  1. It's time starting !
  2. Hello FishC.
  3. It's time ending !
  4. It's used : 0.022337913513183594.
复制代码

但是大家有没有发现,这一次我们不需要再去调用 timeslong() 函数了。

如果我有多个函数需要统计,那么使用起修饰符来就更优雅了:

  1. import time

  2. def timeslong(func):
  3.     def call():
  4.         start = time.time()
  5.         print("It's time starting ! ")
  6.         func()
  7.         print("It's time ending ! ")
  8.         end = time.time()
  9.         return "It's used : %s." % (end - start)
  10.     return call

  11. @timeslong
  12. def myfuna():
  13.     print("Hello World.")

  14. @timeslong
  15. def myfunb():
  16.     print("Hello Python.")

  17. @timeslong
  18. def myfunc():
  19.     print("Hello FishC.")

  20. print(myfuna())
  21. print("========================================")
  22. print(myfunb())
  23. print("========================================")
  24. print(myfunc())
复制代码

实现结果:

  1. It's time starting !
  2. Hello World.
  3. It's time ending !
  4. It's used : 0.023639202117919922.
  5. ========================================
  6. It's time starting !
  7. Hello Python.
  8. It's time ending !
  9. It's used : 0.01770305633544922.
  10. ========================================
  11. It's time starting !
  12. Hello FishC.
  13. It's time ending !
  14. It's used : 0.014674186706542969.
复制代码

通过修饰符主要达到的目标是使得整个代码看起来更加美观,仅此而已。

另外,我们还可以进一步“优雅”,

那就是把它封装成类:

  1. import time

  2. class timeslong(object):
  3.     def __init__(self, func):
  4.         self.func = func

  5.     def __call__(self):
  6.         start = time.time()
  7.         print("It's time starting ! ")
  8.         self.func()
  9.         print("It's time ending ! ")
  10.         end = time.time()
  11.         return "It's used : %s." % (end - start)

  12. @timeslong
  13. def myfuna():
  14.     print("Hello World.")

  15. @timeslong
  16. def myfunb():
  17.     print("Hello Python.")

  18. @timeslong
  19. def myfunc():
  20.     print("Hello FishC.")

  21. print(myfuna())
  22. print("========================================")
  23. print(myfunb())
  24. print("========================================")
  25. print(myfunc())
复制代码

实现的结果是一样的:

  1. It's time starting !
  2. Hello World.
  3. It's time ending !
  4. It's used : 0.03470897674560547.
  5. ========================================
  6. It's time starting !
  7. Hello Python.
  8. It's time ending !
  9. It's used : 0.01266622543334961.
  10. ========================================
  11. It's time starting !
  12. Hello FishC.
  13. It's time ending !
  14. It's used : 0.014008522033691406.
复制代码

其实呀,Python 也有内置的修饰符,它们分别是 staticmethodclassmethodproperty,作用分别是把类中定义的实例方法变成静态方法、类方法和类属性。

简单地举个例子,如果我们将类这么写:

  1. >>> class Hello(object):
  2. ...     def print_hello(cls):
  3. ...         print("Hello FishC")
复制代码

那么直接使用 类名.函数() 的方式调用就会报错:

  1. >>> Hello.print_hello()
  2. Traceback (most recent call last):
  3.   File "<pyshell#2>", line 1, in <module>
  4.     Hello.print_hello()
  5. TypeError: print_hello() missing 1 required positional argument: 'cls'
复制代码

但是,只需要在类里面的函数名上方加上一个 @classmethod 修饰符:

  1. >>> class Hello(object):
  2. ...     @classmethod
  3. ...     def print_hello(cls):
  4. ...         print("Hello FishC")
复制代码

那么问题就迎刃而解了:

  1. >>> Hello.print_hello()
  2. Hello FishC
复制代码

因为给 @classmethod 修饰过后,print_hello() 就变成了类方法,可以直接通过 Hello.print_hello() 调用,而无需绑定实例对象了。

评分

参与人数 28荣誉 +89 鱼币 +80 贡献 +46 收起 理由
sky19791111 + 5 + 5 + 3
TC_DHL + 1 装饰器这块讲解的确实比较云里雾里, 不够透.
看图图的孩子 + 1 + 1 + 1 看起来很像是装饰器讲的那章
KIBETY + 5 + 2 + 3 good
Luious + 5 + 5 + 3
革命年 + 1 + 1 我居然看懂了?
aaron.yang -1 -1 新手无法理解
南聊菜瓜 + 1 + 3 + 1 ???
种好现 + 5 + 5 + 3 云里雾里,做题试试
TheOne000 + 1 不是很明白啊

查看全部评分

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

使用道具 举报

发表于 2014-9-9 10:21:10 | 显示全部楼层
没大看懂- -。。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 4 反对 1

使用道具 举报

发表于 2014-12-26 11:31:12 | 显示全部楼层
本帖最后由 猴子请来的救兵 于 2014-12-26 14:23 编辑

看不懂。。。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2014-12-31 16:24:34 | 显示全部楼层
这方法太好了!
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 1 反对 1

使用道具 举报

发表于 2015-1-1 01:18:19 | 显示全部楼层
那三个内置修饰符没看懂怎么用法,得研究一下了。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2015-1-20 17:06:47 | 显示全部楼层
没看懂,比如使用修饰符,为什么不需要将func()重新在timeslong中重新写一遍,没有体现出来,只说了不需要重写一遍,所以没看明白。。。:sad
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 2 反对 0

使用道具 举报

发表于 2015-1-20 20:34:03 | 显示全部楼层
现在明白了一点点了,智商是硬伤
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 1 反对 0

使用道具 举报

发表于 2015-1-22 20:34:42 | 显示全部楼层
我写了一个简单的装饰器:
def fun1(fx):
    fx(2,5)
@fun1
def fun2(a,b):
    s=a+b
    print(s)
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 7 反对 2

使用道具 举报

发表于 2015-4-8 11:06:40 | 显示全部楼层
有点晕!!!!
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2015-4-14 13:25:05 | 显示全部楼层
有点像matlab里的那个函数修饰符@
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2015-7-12 16:52:59 | 显示全部楼层
有点懂了,可还是迷糊
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2015-7-15 19:42:17 | 显示全部楼层
def deco(func):
    print('有点蛋疼。。。')
    func()
    return func
@deco
def myfunc():
    print('真心的。。。')
myfunc()
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2015-7-26 09:28:57 | 显示全部楼层
半懂~
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2015-9-14 15:01:04 | 显示全部楼层
迷迷糊糊的
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2015-9-16 17:22:47 | 显示全部楼层
这是2.X版本的?3.X运行不了
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2015-11-7 10:19:25 From FishC Mobile | 显示全部楼层
这是给会的人看的吧
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2015-11-11 13:38:27 | 显示全部楼层
不太懂啊
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2015-11-11 15:23:31 | 显示全部楼层
楼主能再说清楚点吗?
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2015-11-19 14:52:53 | 显示全部楼层
看蒙了,还是不明白:sad
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2015-12-6 12:21:37 | 显示全部楼层
悄悄哈
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

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

本版积分规则

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

GMT+8, 2024-4-27 09:53

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

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