- 作用:
- 在不改变原来函数的代码情况下,进行修改,或者增加函数的功能
- 装饰器本质上就是一个闭包
-
- 雏形:
- 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)
-