美文网首页
Python 修饰器 - 胖子老板:年终了,是时候给蓝利群加1元

Python 修饰器 - 胖子老板:年终了,是时候给蓝利群加1元

作者: Devops海洋的渔夫 | 来源:发表于2019-01-02 00:25 被阅读88次

    仅供学习,转载请注明出处

    装饰器

    装饰器是程序开发中经常会用到的一个功能,用好了装饰器,开发效率如虎添翼,所以这也是Python面试中必问的问题,但对于好多初次接触这个知识的人来讲,这个功能有点绕,自学时直接绕过去了,然后面试问到了就挂了,因为装饰器是程序开发的基础知识,这个都不会,别跟人家说你会Python, 看了下面的文章,保证你学会装饰器。

    在学习装饰器之前,首先要懂得闭包,如果还不懂,那么请点击这里,进行阅读一下。

    那么理解完毕了闭包的功能之后,下面我们来看看一个示例,来理解一下装饰器。

    装饰器示例:胖子老板头疼给每个商品价格都加1元

    年终到了,大部分人都会到店铺买点小礼物之类的东西去送人。此时此景,胖子老板就想把店铺的付费系统价格都临时加1元,这样的话,大家也不介意。

    但是由于商品计算价格的函数太多啦,一个个去写,感觉好烦。
    下面来看看。

    In [37]: def Smoke_Price():
        ...:     return 17
        ...: 
    
    In [38]: def Binlang_Price():
        ...:     return 10
        ...: 
    
    In [39]: sp = Smoke_Price
    
    In [41]: sp()
    Out[41]: 17
    
    In [42]: bl = Binlang_Price
    
    In [43]: bl()
    Out[43]: 10
    

    除了这两个商品,还有很多很多的商品,那么怎么来改写呢?

    首先用闭包的方式来看看能否实现:

    In [44]: def add_price(price):
        ...:     def Smoke_Price():
        ...:         return 17 + price
        ...:     return Smoke_Price
        ...: 
        ...: 
    
    In [45]: ap = add_price(1)
    
    In [46]: ap()
    Out[46]: 18
    
    In [47]: 
    

    实现是实现了,但是要每次都写一个这样的闭包,好烦呢。那不就是每个商品的计算价格的函数都要写一遍?
    有没有更加好的方式呢?

    使用修饰器的方式

    def add_price(Smoke_price):
        def call_func():
            print("------ 增加了修饰器 ------")
            return Smoke_price() + 1
        return call_func
    
    @add_price
    def Smoke_price():
        return 17
    
    sp = Smoke_price()
    
    print(sp)
    

    运行看看:

    F:\pythonProject\test>python test2.py
    ------ 增加了修饰器 ------
    18
    
    F:\pythonProject\test>
    

    从上面的结果来看,只要加上 @add_price 就可以实现了。

    那么这里面的实现原理是怎么样的呢?

    In [1]: def Smode_price():
       ...:     return 17
       ...: 
    
    In [2]: def add_price(Smode_price):
       ...:     def call_func():
       ...:         return Smode_price() + 1
       ...:     return call_func
       ...: 
    
    In [3]: sp = add_price(Smode_price)
    
    In [4]: sp()
    Out[4]: 18
    
    In [5]: 
    

    上面函数的调用过程等价于使用add_price再次调用Smoke_price。

    从上面的例子中看出,在写装饰器的时候,我将价格 1 元写死了,那么如果要写价格为 2元 呢?是不是又要写一个装饰器?

    下面来写一个带参数的装饰器示例

    def set_price(price):
        def add_price(Smoke_price):
            def call_func():
                print("------ 增加了修饰器 ------")
                return Smoke_price() + price
            return call_func
        return add_price
    
    @set_price(1)  ## 写入装饰器的参数 price = 1
    def Smoke_price():
        return 17
    
    sp = Smoke_price()
    
    print(sp)
    

    只要在add_price(Smoke_price)外部再包一层闭包,淡定写上参数price,这样就可以啦。
    运行如下:

    F:\pythonProject\test>python test2.py
    ------ 增加了修饰器 ------
    18
    

    上面已经完成了大部分装饰器的功能了,此情此景下,胖子老板想要给Smoke_price写几个参数,用来计算打折,又想要给Binlang_price写几个参数,如果中奖了,那么就直接不需要给钱了。

    那么这个需求该怎么去实现呢?

    首先先看看更改参数后的方法

    ## 修改Smoke_price方法,添加折扣discount参数
    In [1]: def Smoke_price(discount):
       ...:     price = 17
       ...:     return price * discount
       ...: 
    
    In [3]: sp = Smoke_price(0.8)
    
    In [4]: sp
    Out[4]: 13.600000000000001
    
    In [5]: 
    
    ## 设置isWin参数,判断购买槟榔是否中将,中奖就不用付款啦。
    In [5]: def Binlang_price(isWin):
       ...:     if isWin:
       ...:         return 0
       ...:     else:
       ...:         return 10
       ...: 
    
    ## 设置槟榔中奖,为True
    In [6]: bp = Binlang_price(True)
    
    In [9]: print(bp)
    0
    
    ## 设置槟榔没有中奖,为Flase
    In [11]: bp = Binlang_price(False)
    
    In [12]: bp
    Out[12]: 10
    
    In [13]: 
    
    

    从上面看出,Smoke_price(discount)Binlang_price(isWin)两个方法,如果要被修饰器调用,那么当然在修饰器中,调用这两个方法的时候,也要将参数传入。

    此时就可以使用 *args,**kwargs 两个可变的形参来处理。

    下面来实现一下增加参数后的修饰器:

    def set_price(price):
        def add_price(func):
            def call_func(*args,**kwargs):
                print("------ 增加了修饰器 ------")
                return func(*args,**kwargs) + price
            return call_func
        return add_price
    
    # 计算香烟的价格
    @set_price(1)
    def Smoke_price(discount):
        price = 17
        return price * discount
    
    sp = Smoke_price(0.8)
    
    print("蓝利群的价格=%0.2f" % sp)
    
    # 计算槟榔的价格
    @set_price(1)
    def Binlang_price(isWin):
        if isWin:
            return 0
        else:
            return 10
    
    bp = Binlang_price(True)
    
    print("槟榔的价格=%d" % bp)
    

    运行如下:

    F:\pythonProject\test>python test2.py
    ------ 增加了修饰器 ------
    蓝利群的价格=14.60
    ------ 增加了修饰器 ------
    槟榔的价格=1
    
    F:\pythonProject\test>
    

    满足了这些要求了之后,胖子老板还想计算多一个运费,然后直接在原来的方法中返回一个 运费 + 价格 的总数,这个又该怎么处理呢?

    使用多个修饰器,来解决这个问题

    ## 设置计算运费
    def freight(func):
        # 运费10元
        freight_price = 10
        def call_func(*args,**kwargs):
            print("---------1 计算添加运费 --------------")
            return func(*args,**kwargs) + freight_price
        return call_func
    
    
    ## 设置价格加价
    def set_price(price):
        def add_price(func):
            def call_func(*args,**kwargs):
                print("------ 2.增加了修饰器 ------")
                return func(*args,**kwargs) + price
            return call_func
        return add_price
    
    # 计算香烟的价格
    @freight
    @set_price(1)
    def Smoke_price(discount):
        price = 17
        return price * discount
    
    sp = Smoke_price(0.8)
    
    print("蓝利群的价格=%0.2f" % sp)
    
    # 计算槟榔的价格
    @freight
    @set_price(1)
    def Binlang_price(isWin):
        if isWin:
            return 0
        else:
            return 10
    
    bp = Binlang_price(True)
    
    print("槟榔的价格=%d" % bp)
    

    运行如下:

    F:\pythonProject\test>python test2.py
    ---------1 计算添加运费 --------------
    ------ 2.增加了修饰器 ------
    蓝利群的价格=24.60
    ---------1 计算添加运费 --------------
    ------ 2.增加了修饰器 ------
    槟榔的价格=11
    
    F:\pythonProject\test>
    

    好啦,从上面来看,直接写多一个修饰器,用来计算增加运费即可。
    其实修饰器就是多层闭包函数的调用,执行的顺序则是从上至下逐个修饰器执行的。

    关注微信公众号,回复【资料】、Python、PHP、JAVA、web,则可获得Python、PHP、JAVA、前端等视频资料。

    相关文章

      网友评论

          本文标题:Python 修饰器 - 胖子老板:年终了,是时候给蓝利群加1元

          本文链接:https://www.haomeiwen.com/subject/jzgolqtx.html