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