引子

  python 中的装饰器是oop(面向对象编程)设计模式、之装饰器模式的一个应用、由于有语法糖衣的缘故、所以写起来也更加方便

从一个比较经典的应用场景来讲解装饰器

  有过一定编程经历的工程师、应该都遇到过这样的场景。有一些老的API过时了但是在一段时间内它还是可用的,只是平台会把

  它标记为不推荐、也就是说这个API在新的版本里应该不会存在了。比如python-2.x 的时候有raw_input这个函数、但是到了  

  python-3.x的时候就没有了,在过渡时期平台通常会把将要过时的API标记成“过时”。它是怎么做到的呢?我觉得可行的方法

  有两个 1): 用工程师的“寿命”为代价通过手工劳动解决问题   2): 用装饰器优雅的解决

用寿命来解决问题

  1.1 假设你编写了一个非常牛逼的库、里面包含了一个非常牛逼的函数、它可以完成两个数相加。一开始你的代码是这样的

def add_fun(x,y):
"""
实现两个数相加、并返回合
"""
return x+y

  1.2 一段非常长的时间后、你的库在社区中大火、大家也都称你为大神;可是你突然发现了一个问题 add_fun 这个函数以“_fun”

  结尾真的够pythonic吗? 后来你还是决定把它改成add这样的函数名,可是有太多的程序依赖于你这个库的add_fun函数了,

  如果你突然把这个add_fun函数给改了,那些依赖于这个函数的程序由于再也找不到这个函数了,那么它们会报错,这个明显

  不是你想看到的;最后你还是决定单独增加一个add方法同时保留add_fun

def add_fun(x,y):
"""
实现两个数相加、并返回合
"""
return x+y def add(x,y):
"""
实现两个数相加、并返回合
"""
return x+y

  1.3 你开始为你这一个改动付出代价(网络上一时有无数人都在问你同一个问题),无数的人在问你为什么会有两上功能完全一样的函数?

  于是你把这个问题加到了FQA列表、并且还在你的代码中明确的指出了“add_fun已经过时”

def add_fun(x,y):
"""
实现两个数相加、并返回合
""" print("add_fun 函数已经过时")
return x+y def add(x,y):
"""
实现两个数相加、并返回合
"""
return x+y

  1.4 问题是解决了,几天过你可能会发现自己掉粉了,多数人对你这种简单粗暴的方法表示了失望。 有来说一下你的改法有什么问题吧、

  1): 你给出函数没办法“封闭”,“封闭”是oop编程中的一个术语,指的你定义好的类、函数应该是功能上完备的,不应该再改了,想

  一下如果“场效应管”、“二极管”、“pn结” 这种基础元器件动不动就要改一下,这种感觉就像你是在对一个身在100楼的程序猿说,

  你好好上你的班、不过我要修一下大楼的地基。回到程序上来你用什么来保存你的改动不会引入新的bug ?

  2): 一个函数还好、如果你成千上万个?那么你这成千上万个都没有封闭、而且每一个你都要改一下、你工作量也不是一般的小、人在

  重复劳动下容易出错。

巧用装饰器解决问题

  先定义一个函数它可以用来包装那些过时的函数、代码如下

def deprecated(fun):
"""deprecated函数会返回一个叫inner的函数、inner函数会返回
fun调用的结果,与直接调用fun得到值不同的是inner会先打印一行提示
表明fun已经过时
"""
def inner(x,y):
print("{fun.__name__} 函数已经过时".format(fun=fun))
return fun(x,y)
return inner def add_fun(x,y):
"""
实现两个数相加、并返回合
"""
return x+y add_fun = deprecated(add_fun) #包装add_fun函数 def add(x,y):
"""
实现两个数相加、并返回合
"""
return x+y if __name__=="__main__":
print(add_fun(1,1))

  调用时的输出

python3 dc.py

add_fun 函数已经过时

  

  从上面的例子我们看出装饰器并没有什么特别这只不过是一个“返回可调用对象的可调用对象”、下面我们讲一下装饰器的“语法糖衣 @写法”

def deprecated(fun):
"""deprecated函数会返回一个叫inner的函数、inner函数会返回
fun调用的结果,与直接调用fun得到值不同的是inner会先打印一行提示
表明fun已经过时
"""
def inner(x,y):
print("{fun.__name__} 函数已经过时".format(fun=fun))
return fun(x,y)
return inner @deprecated # 使用@写法来实现包装
def add_fun(x,y):
"""
实现两个数相加、并返回合
"""
return x+y def add(x,y):
"""
实现两个数相加、并返回合
"""
return x+y if __name__=="__main__":
print(add_fun(1,1))

  从上面可以看出在使用装饰器来处理代码的情况下,add_fun是“封闭”的 ,@写法与上面的函数调用方式下包装add_fun是等价的。输出结果如下

python3 dc.py
add_fun 函数已经过时

最新文章

  1. Mono 3.2.3 TCP吞吐性能测试报告
  2. Dagger2 (三) 总结篇
  3. 构建自己的PHP框架--定义ORM的接口
  4. css让图片作为按钮的背景并且大小合适
  5. JS识记
  6. Ubuntu 12.10
  7. C#实战Microsoft Messaging Queue(MSMQ)消息队列(干货)
  8. VS2013 试用版到期 解决办法
  9. linux 从命令行自动识别文件并将其打开的命令
  10. JSON API in Javascript
  11. 实践过配置成功的VNC安装配置
  12. gem安装时出现 undefined method `size' for nil:NilClass (NoMethodError) 的解决办法
  13. Adapter常用的实现--BaseAdapter
  14. (原)caffe在ubuntu中设置GPU的ID号及使用多个GPU
  15. Android各种效果集合
  16. C++ string数据类型的实现
  17. highcharts数据标签显示在柱状图里面解决办法
  18. java 获取当天(今日)零点零分零秒
  19. 嵌入式linux系统中,lsusb出现unable to initialize libusb: -99 解决办法 【转】
  20. 【struts2】Struts2的系统架构

热门文章

  1. Mysql的union
  2. 浅谈关于QT中Webkit内核浏览器
  3. javascript数字转大写
  4. Axis 发布、调用WebService(转)
  5. 整合ssm框架之配置文件
  6. Qt5.9静态库编译VS2015-x64
  7. Qt Installer Framework 使用说明(一)
  8. RHEL7 MariaDB测试
  9. Linux特殊的文件控制权限FACL
  10. 转:TCP/IP协议栈的基本工作原理