装饰器函数是在不改变原来函数的情况下,添加额外功能的函数。装饰器函数内部还有一个函数,返回值是内部函数名。定义装饰器函数的语法格式如下:
def 装饰器函数名(参数1):
函数体
def 内部函数名(参数2):
函数体
return 内部函数名
其中,参数1接收原函数的函数名;参数2接收原函数的参数。
例如,某月饼零售价为5元一个,但是礼盒装月饼(8个装)为200元一盒,那么同样的月饼,使用礼盒包装后,可能就加价160元。
首先定义两个函数,一个是月饼函数,另一个是礼盒函数。
定义月饼函数,代码如下:
def cake():
print('五仁月饼零售价5元')
调用月饼函数,代码如下:
cake()
调用月饼函数后,运行结果:
五仁月饼零售价5元
定义礼盒函数,代码如下:
def box():
print('礼盒加价160元')
def get_cake():
cake()
调用礼盒函数,代码如下:
box()
调用礼盒函数后,运行结果:
礼盒加价160元
运行结果显然不符合预期,没有打印“五仁月饼零售价5元”,这是因为只是在礼盒函数内定义了get_cake()函数,但是没有调用这个函数。修改礼盒函数,代码如下:
def box():
print('礼盒加价160元')
def get_cake():
cake()
get_cake() # 调用函数
再次调用礼盒函数后,运行结果:
礼盒加价160元
五仁月饼零售价5元
但是,同一种礼盒可能会装不同的月饼,现有三种月饼分别为五仁、豆沙、蛋黄,这三种月饼的零售价分别为5元、5元、8元。
定义豆沙月饼函数,代码如下:
def cake1():
print('豆沙月饼零售价5元')
定义蛋黄月饼函数,代码如下:
def cake2():
print('蛋黄月饼零售价8元')
下面分别给礼盒函数传递三个原函数的名称,修改礼盒函数,代码如下:
def box(fun): # 添加参数
print('礼盒加价160元')
def get_cake():
fun()
get_cake()
这样就分别实现了三种打印效果,三种月饼都可以被礼盒包装了。
重新调用礼盒函数,代码如下:
box(cake)
box(cake1)
box(cake2)
调用礼盒函数后,运行结果:
礼盒加价160元
五仁月饼零售价5元
礼盒加价160元
豆沙月饼零售价5元
礼盒加价160元
蛋黄月饼零售价8元
目前月饼函数是无参数、无返回值的。给月饼函数添加返回值,代表月饼的个数,代码如下:
def cake():
print('五仁月饼零售价5元')
return 4 # 添加返回值
而礼盒函数也需要进行相应的修改,代码如下:
def box(fun):
print('礼盒加价160元')
def get_cake():
num = fun()
return num
return get_cake()
调用礼盒函数,代码如下:
nums = box(cake)
print('获取数量:%d' % nums)
调用礼盒函数后,运行结果:
礼盒加价160元
五仁月饼零售价5元
获取数量:4
目前原函数是cake(),其装饰器函数是box()。Python中,原函数和装饰器函数的修饰关系类似于月饼和礼盒的关系。在定义原函数之前,使用“@+装饰器函数名”的形式得到装饰关系。
给月饼函数添加修饰关系,代码如下:
@box
def cake():
print('五仁月饼零售价5元')
return 4
而礼盒函数也需要进行相应的修改,代码如下:
def box(fun):
print('礼盒加价160元')
def get_cake():
num = fun()
return num
return get_cake # 返回值中删除函数名后的括号
在调用时不需要再写礼盒函数名,就像最终吃的是月饼,因此,直接调用月饼函数即可,代码如下:
nums = cake()
print('获取数量:%d' % nums)
调用月饼函数后,运行结果:
礼盒加价160元
五仁月饼零售价5元
获取数量:4
由运行结果可知,此时不需要写修饰器函数名,也可达到同样的效果,这说明了装饰器的作用。
常见的函数一般是有参数的,装饰器函数的参数用于接收原函数名,内部函数的参数用于接收原函数的参数。有时原函数中参数的数量和类型是无法事先确定的,可以使用*args和**kwargs,即可变位置参数和可变关键字参数,这样无论任何参数都可以接收。
修改月饼函数,添加参数n,代表月饼的个数,代码如下:
@box
def cake(n): # 添加参数
print('五仁月饼零售价5元')
return n # 修改返回值
而礼盒函数也需要进行相应的修改,代码如下:
def box(fun):
print('礼盒加价160元')
def get_cake(*args, **kwargs): # 内部函数添加参数
num = fun(*args, **kwargs)
return num
return get_cake
再次调用月饼函数,代码如下:
nums = cake(4)
print('获取数量:%d' % nums)
再次调用月饼函数后,运行结果:
礼盒加价160元
五仁月饼零售价5元
获取数量:4