python3 装饰器应用举例

 

引子

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

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

 

posted on 2018-07-14 13:08  蒋乐兴的技术随笔  阅读(1130)  评论(0编辑  收藏  举报

导航