引子

  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 函数已经过时

python3 装饰器应用举例的更多相关文章

  1. 净心诀---python3装饰器

    python3装饰器 装饰器作用 简单理解:可以为已有函数添加额外功能 例: 已有2个函数如下 def MyFunc1(): print("This is a print function1 ...

  2. python3 装饰器全解

    本章结构: 1.理解装饰器的前提准备 2.装饰器:无参/带参的被装饰函数,无参/带参的装饰函数 3.装饰器的缺点 4.python3的内置装饰器 5.本文参考 理解装饰器的前提:1.所有东西都是对象( ...

  3. python3 装饰器

    #Author by Andy#_*_ coding:utf-8 _*_#装饰器的原则及构成:# 原则:# 1.不能修改被装饰函数的源代码.# 2.不能修改被装饰函数的调用方式.# 3.不能改变被装饰 ...

  4. python3 装饰器初识 NLP第三条

    还是先抄一条NLP假设... 三,有效果比有道理更重要   光说做法有道理或者正确而不顾是否有效果,是在自欺欺人. 在三赢(我好,人好,世界好)的原则基础上追求效果,比坚持什么是对的更有意义. 说道理 ...

  5. python3装饰器用法示例

    装饰器在编写后台的逻辑时有可能会用到,比方说一个场景:公司的员工想要登录自己公司的考勤记录系统去修改自己的考勤,以前是随便谁都有权限去修改,这样老板不同意了,现在,要在你登录前加一个权限验证的逻辑,如 ...

  6. python3装饰器

    由于函数也是一个对象,而且函数对象可以被赋值给变量,所以,通过变量也能调用该函数. >>> def now(): ... print('2015-3-25') ... >> ...

  7. python3 装饰器修复技术@wraps到底是什么?

    Python 装饰器中的@wraps的作用:    装饰器的作用:    在不改变原有功能代码的基础上,添加额外的功能,如用户验证等    @wraps(view_func)的作用:     不改变使 ...

  8. Python3装饰器的使用

    装饰器 简易装饰器模板 def wrapper(func): def inner(*args,**kwargs): print('主代码前添加的功能') ret=func(*args,**kwargs ...

  9. python3装饰器-进阶

    一.wraps 作用:优化装饰器 from functools import wraps # 导入wraps def wrapper(f): @wraps(f) # wraps的语法糖 def inn ...

随机推荐

  1. mysqld.exe

    mysqld.exe是mysql的服务端程序,开启之后才能使用mysql.exe 将mysql安装成服务很简单: mysqld.exe install mysql 删除服务也很简单: sc delet ...

  2. MapReduce三种路径输入

    目前为止知道MapReduce有三种路径输入方式.1.第一种是通过一下方式输入: FileInputFormat.addInputPath(job, new Path(args[0]));FileIn ...

  3. VB.NET版+三层实现登陆

    三层已经学了一些时间了,開始认为自己能够用C#敲代码了,就用C#写了一个实现登陆的,真正再用在机房中.还是认为非常吃力的,所以.决定用vb.net敲了.以下是我用vb.net实现的登陆.能够给大家做一 ...

  4. Eclipse远程连接HBase

    在Eclipse下新建一个Map/Reduce项目,并将以下jar添加到Build path: 程序代码: package thathbase; import java.io.IOException; ...

  5. node.js模块化写法入门

    子模块的写法: function SVN(){ console.log('svn initialized'); return this; } function getInstance() { cons ...

  6. Java千百问_05面向对象(005)_接口和抽象类有什么差别

    点击进入_很多其它_Java千百问 1.接口和抽象类有什么差别 在Java语言中.抽象类abstract class和接口interface是抽象定义的两种机制. 正是因为这两种机制的存在,才赋予了J ...

  7. JAVA中的CountDownLatch、CyclicBarrier、Semaphore的简单测试

    因公司需要做一个对于CountDownLatch的分享,特写了此blog. 具体细节可以参见:小结java自带的跟锁相关的一些类 在做这个分享的过程中发现了Main和junit的运行的区别,在另外一个 ...

  8. Windows下 VS2015编译levelDB(nmake)

    VS2015编译levelDB Leveldb是一个google实现的非常高效的kv数据库,非常适合嵌入到程序中.如果有简单的key-value数据库需求,而又想使用一个数据库服务的话,levelDB ...

  9. Inno Setup入门(九)——修改安装过程中的文字显示

    前面说到过可以使用不用的语言文件实现不同的显示方式,方便与国际接轨,事实上即使没有语言文件也可以实现修改.[Messages] 段用于定义安装程序和卸载程序中显示的消息.一般不需要创建 [Messag ...

  10. 管理多tomcat实例的shell脚本

    为了简化tomcat的部署复杂度, 把以前单独配置的脚本提出来做了一个带参数的, 可以用于单机环境下的多tomcat实例管理. 其中deploy功能, 会将指定的模块war按日期时间更名备份后, 再部 ...