前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Python 修饰器 - 胖子老板:年终了,是时候给蓝利群加1元了。

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

作者头像
Devops海洋的渔夫
发布2019-06-02 13:44:01
4060
发布2019-06-02 13:44:01
举报
文章被收录于专栏:Devops专栏Devops专栏

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

装饰器

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

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

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

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

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

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

下面来看看。

代码语言:javascript
复制
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

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

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

代码语言:javascript
复制
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]: 

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

有没有更加好的方式呢?

使用修饰器的方式

代码语言:javascript
复制
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)

运行看看:

代码语言:javascript
复制
F:\pythonProject\test>python test2.py
------ 增加了修饰器 ------
18

F:\pythonProject\test>

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

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

代码语言:javascript
复制
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元 呢?是不是又要写一个装饰器?

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

代码语言:javascript
复制
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,这样就可以啦。

运行如下:

代码语言:javascript
复制
F:\pythonProject\test>python test2.py
------ 增加了修饰器 ------
18

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

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

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

代码语言:javascript
复制
## 修改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 两个可变的形参来处理。

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

代码语言:javascript
复制
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)

运行如下:

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

F:\pythonProject\test>

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

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

代码语言:javascript
复制
## 设置计算运费
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)

运行如下:

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

F:\pythonProject\test>

好啦,从上面来看,直接写多一个修饰器,用来计算增加运费即可。

其实修饰器就是多层闭包函数的调用,执行的顺序则是从上至下逐个修饰器执行的。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019.01.02 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 装饰器
  • 装饰器示例:胖子老板头疼给每个商品价格都加1元
  • 首先先看看更改参数后的方法
  • 使用多个修饰器,来解决这个问题
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档