作用:
在不改变原来函数的代码情况下,进行修改,或者增加函数的功能
装饰器本质上就是一个闭包
雏形:
def wrapper(fn): wrapper: 装饰器 , fn: 目标函数
def inner():
# 在目标函数执行前的一些动作
fn()
# 在目标函数执行后的一些动作
return inner #千万别加(),这里是返回一个函数名。如果加(),表示返回函数执行的结果
@wrapper
def fn(): #目标函数
print("xxxxxxx")
功能:
执行目标函数fn, 相当于执行了wrapper函数里闭包的inner函数过程
1. 装饰器方式一
def lunch(fuc):
def inner():
print("water hand")
fuc()
print("su kou")
return inner
def eat():
print("eat somethings")
lunch(eat) #这里返回是一个函数名inner,函数名在内存中指向一个地址
l = lunch(eat) # l 和 inner 同时指向同一个内存地址
l() #这里是执行inner函数体
#执行结果
water hand
eat somethings
su kou
2.装饰器方式二
def lunch(fuc):
def inner():
print("water hand") #在执行eat()函数前需要增加的动作
fuc() #这里是lunch函数的形参,将以eat函数名作为形参,这里就是执行eat()函数一样。
print("su kou") #在执行eat()函数前需要增加的动作
return inner
@lunch # 这里相当于eat = lunch(eat),由于lunch(eat)返回inner函数名,相当于eat()执行,就换成inner()执行一样。
def eat():
print("eat somethings")
#执行eat()函数体,相当于调用lunch的函数,把eat函数名作为lunch函数的形参fuc传入,在不改变eat函数本身的代码,增加了一些功能
eat() #执行eat()
总结:
上面两种方法,都是可以,但是看自己的需求
二。扩展
def lunch(fuc):
def inner(name, number): #使用装饰器后,执行eat函数相当于执行inner函数,那这里也要有两个形参
print("water hand")
fuc(name, number) #在执行inner函数时,这个是调用目标eat函数,由于下面eat函数定义有两个实参,因此这里也要有对应的形参,并且数量要一样
print("su kou")
return inner
@lunch
def eat(name, num): #这里函数有实参
print("吃{}水果,吃了{}个".format(name, num))
#如果eat有定义实参,而装饰器没有定义形参,就会报错类似这样,# TypeError: inner() takes 0 positional arguments but 2 were given
eat("apple",5)
执行结果:
water hand
吃apple水果,吃了5个
su kou
三,扩展三
1.如果这个food装饰器要被多个函数调用,并且是同一个功能,并且多个函数的实参是不一样的,因此就需要使用*args,来接收实参。这样不管调用这个装饰器的函数,实参多少个都可以匹配,
def food(fnc):
def inner(*args): #多个形参
print("water hand")
fnc(*args) #多个形参
print("su kou")
return inner
@food
def drink(name, num, money): #三个实参
print("喝了{}酒,喝了{}瓶,一共花了{}块钱。".format(name, num, money))
drink("葡萄", 10, 8888)
@food
def eat(name, num): #两个实参
print("吃{}水果,吃了{}个".format(name, num))
eat("榴莲",3)
#执行结果
water hand
喝了葡萄酒,喝了10瓶,一共花了8888块钱。
su kou
water hand
吃榴莲水果,吃了3个
su kou
四。扩展四
1:下面的*args, **kwargs,这里不管位置形参,还是关键字形参都包含了,表示0个,或者多个形参匹配
注意要点:
*args, **kwargs前面的 * 或者 ** ,表示把args元组和kwargs字典打散成位置参数 ,以及关键字参数传递进去,并不是说args看成一个元组作为参数传递进去。
def food(fnc):
def inner(*args, **kwargs):
print("water hand")
fnc(*args, **kwargs)
print("su kou")
return inner
@food
def drink(name, num, money):
print("喝了{}酒,喝了{}瓶,一共花了{}块钱?".format(name, num, money))
drink("葡萄", 10, 8888) #上面*args, **kwargs,表示匹配0个或者多个位置形参,关键字形参,所以你这里没有定义关键字实参,也是对的
drink("葡萄", 10, money=8888) #定义关键字实参,
@food
def eat(name, num):
print("吃{}水果,吃了{}个".format(name, num))
eat("榴莲",3)