装饰器@作用:为函数新增功能,解决重复性的操作,使得代码简洁、更模块化。
例子:
1.无参
原功能函数和业务代码如下:
def checkLogin():
print("登陆验证")
def fss():
print("发说说")
def ftp():
print("发图片")
a = 1
if a == 1:
fss()
checkLogin()
else:
ftp()
checkLogin()
# 代码冗余,需反复调用checkLogin()功能函数
使用装饰器修改如下:
def checkLogin(func):
# 这里是定义一个闭包
def inner():
print("登陆验证")
func()
return inner
# 这里返回inner()函数
def fss():
print("发说说")
fss = checkLogin(fss)
'''相当于
fss = def inner():
print("登陆验证")
func()
即修改了fss函数
'''
def ftp():
print("发图片")
a = 1
if a == 1:
fss()
else:
ftp()
也使用@代替 fss = checkLogin(fss) 语句
def checkLogin(func):
def inner():
print("登陆验证")
func()
return inner
@checkLogin
#类似于将fss作为函数参数,传给checkLogin函数
def fss():
print("发说说")
# fss = checkLogin(fss)
def ftp():
print("发图片")
a = 1
if a == 1:
fss()
else:
ftp()
以上两种方式输出相同,使用@(类似于一种语法糖)可以减少代码量。
注意:
装饰器的执行时间为立刻执行,写了@符号,则立刻执行。
可以使用多个装饰器,从上到下装饰,从下到上执行。
2.含参
原代码:
def zsq():
print("-" * 30)
def pnum(num):
print(num)
zsq()
pnum(123)
添加装饰器
def zsq(func):
def inner(n):
# 在装饰器里添加参数
print("-" * 30)
func(n)
return inner
@zsq
def pnum(num):
print(num)
pnum(123)
疑问:如果要传递两个、三个甚至n个参数怎么办?不停修改装饰器吗?
使用不定长参数!
def zsq(func):
def inner(*args, **kwargs):
# 在装饰器里添加不定长参数
print("-" * 30)
func(*args, **kwargs)
# 元组拆包; 字典拆包
return inner
@zsq
def pnum(num, num2, num3):
print(num, num2, num3)
@zsq
def pnum2(num):
print(num)
pnum(123, 234, num3=666)
pnum2(1234)
输出结果:
为什么pnum2可以只传一个参数?解释如下:
def zsq(func):
def inner(*args, **kwargs):
print("-" * 30)
print(args, kwargs)
return inner
@zsq
def pnum(num, num2):
print(num, num2)
pnum(123, 234)
从输出结构可以看到前两个以元组形式传入,而字典为空。(不定长可以为0)
传递一个参数时,则代表元组中只有一个元素,且字典也为空。
想要字典不为空,则通过关键字参数形式调用:
def zsq(func):
def inner(*args, **kwargs):
# 在装饰器里添加不定长参数
print("-" * 30)
print(args, kwargs)
func(*args, **kwargs)
# 元组拆包; 字典拆包
return inner
@zsq
def pnum(num, num2, num3):
print(num, num2, num3)
# 关键字参数调用形式 num3 = 666
pnum(123, 234, num3 = 666)
代码运行结果如下:
注意:
对有返回值的函数进行装饰时,无论什么场景,要保证函数返回值一致。
调用不同装饰器
def zsq1(func):
def inner():
print("-" * 30)
func()
return inner
def zsq2(func):
def inner():
print("+" * 30)
func()
return inner
def zsq1(func):
def inner():
print("-" * 30)
func()
return inner
def zsq3(func):
def inner():
print("*" * 30)
func()
return inner
@zsq1
def f1():
print("不同分割线的装饰器")
上述代码冗余
利用装饰器修改如下:
def getzsq(char):
def zsq1(func):
def inner():
print(char * 30)
func()
return inner
return zsq1
@getzsq("-") # f1 = zsq(f1)
def f1():
print("不同分割线的装饰器")
带有参数的装饰器:
1. 通过@装饰器(参数)的方式,调用这个函数,并传递参数;并把返回值,再次当作装饰器进行使用。
2. 先计算@后面的内容,把这个内容当作是装饰器。