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

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

装饰器

装饰器是程序开发中经常会用到的一个功能,用好了装饰器,开发效率如虎添翼,所以这也是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、前端等视频资料。

你可能感兴趣的:(4. Python 修饰器 - 胖子老板:年终了,是时候给蓝利群加1元了。)