内容:
装饰器,一装饰多,多装饰一,多装饰多,函数带参数,不定参数,装饰器带参数,类装饰器,functools.wraps。
装饰器感觉就是在不改变原代码的情况给它新添一些功能之类的。
1.装饰器
丢出装饰器长相
def aaa(func):
print("aaa")
def bbb():
print("bbb")
func()
return bbb
@aaa
def test():
print("test")
test()
输出结果是
aaa
bbb
test
原来的函数 test()
,会输出一个"test"
,现在在原基础上,多输出了一点东西。
其中没见过的也就一个@aaa
这个语法糖的效果大概等同于先将test
定义后再加一句test=aaa(test)
执行aaa(test)
,定义一个bbb
函数并将这个函数作为返回值赋给test
来达到效果,使得之后调用test
的时候会调用到装饰器内部定义的函数bbb
,同时bbb
内也能通过参数func
调用到原函数test
。
……………………………………………………………………………………………………………………………………………………
2.一个装饰器能够装饰多个函数
def aaa(func):
print("aaa")
def bbb():
print("bbb")
func()
return bbb
@aaa
def test():
print("test")
@aaa
def test2():
print("test2")
test()
test2()
输出:
aaa
aaa
bbb
test
bbb
test2
理解到了装饰器,这个也不难理解。定义的时候便执行了两次aaa
,调用两个函数也调用了两次bbb
只是参数func
不同。
……………………………………………………………………………………………………………………………………………………
3.多个装饰器来装饰一个函数。
def aaa(func):
print("aaa")
def bbb():
print("bbb")
func()
return bbb
def ccc(func):
print("ccc")
def ddd():
print("ddd")
func()
return ddd
@aaa
@ccc
def test():
print("test")
test()
输出
ccc
aaa
bbb
ddd
test
很多解释是装饰器是从下往上执行的,这是结果。
深入理解一点,
这里@aaa
理当装饰的是
被@ccc
装饰了的test
这一整体
@aaa
@ccc
def test
这种形式大致也可以改为在定义完函数后会再加一句test=aaa(ccc(test))
这就不难理解为什么会先输出ccc
后输出aaa
……………………………………………………………………………………………………………………………………………………
4.多个装饰器装饰多个函数
感觉是废话。
……………………………………………………………………………………………………………………………………………………
5.装饰带参数的函数
def aaa(func):
print("aaa")
def bbb(n):
print("bbb")
func(n)
return bbb
@aaa
def test(n):
print(n)
print("test")
test(5)
输出
aaa
bbb
5
test
test
里带了什么参数,bbb
也就也接受个什么参数就行,调用func
也记得把参数带上就行。
……………………………………………………………………………………………………………………………………………………
6.带不定参数
在一个装饰器修饰多个函数的时候,各个函数的参数不同,那就可以用不定参数。
def aaa(func):
print("aaa")
def bbb(*args):
print("bbb")
func(*args)
return bbb
@aaa
def test(n):
print(n)
print("test")
@aaa
def test2(x,y):
print(x+y)
print("test2")
test(5)
test2(3,4)
输出
aaa
aaa
bbb
5
test
bbb
7
test2
还有bbb(*args,**kwargs)
*args
表示多个无名参数,他是一个tuple
**kwargs
表示多个带关键字参数,是个dict
需要什么用什么就行,同时用需要*args
在前面。
……………………………………………………………………………………………………………………………………………………
7.装饰器带参数
效果如下
def ccc(flag):
def aaa(func):
print("aaa")
def bbb():
if flag:
print("11111")
else:
print("22222")
func()
return bbb
return aaa
@ccc(True)
def test1():
print("test1")
@ccc(False)
def test2():
print("test2")
test1()
test2()
输出:
aaa
aaa
11111
test1
22222
test2
这种情况的时候用这个能少写一段代码hh
……………………………………………………………………………………………………………………………………………………
8.类装饰器
和普通的函数的装饰器有一点点区别,本质上还是就那样。
样子大概是
class aaa(object):
def __init__(self,func):
print("aaa")
self.__func=func
def __call__(self):
print("bbb")
self.__func()
@aaa
def test():
print("test")
test()
输出:
aaa
bbb
test
类装饰器的时候 @aaa
也还是相当于在定义完test
后加一句test=aaa(test)
,毕竟在python里万物皆对象。
定义aaa
的一个对象test
,执行构造方法,将原函数test
作为参数func
带入,并赋给类中的__func
之后在执行test()
的时候便会等同于执行test.__call__()
,达到之前装饰器效果。
类装饰器会更灵活一些,封装性也更好。
……………………………………………………………………………………………………………………………………………………
9.functools
装饰器有个缺点,原函数的元信息不见了。
如下:
def aaa(func):
print("aaa")
def bbb():
print("bbb")
func()
return bbb
@aaa
def test():
print("test")
test()
print(test.__name__)
输出
aaa
bbb
test
bbb
毕竟test
已经被我们覆盖掉了。
所以functools
模块
提供了一个装饰器@functools.wraps
如下:
import functools
def aaa(func):
print("aaa")
@functools.wraps(func)
def bbb():
print("bbb")
func()
return bbb
@aaa
def test():
print("test")
test()
print(test.__name__)
输出:
aaa
bbb
test
test
用这个装饰器再来修饰bbb
便能解决之前的问题。
以上便是我对装饰器的理解。