一. @语法糖的理解
一般出现情况为:
@funcA
def funB():
...
转换成更容易理解的语句为:
temp = funcA(funcB)
funcB = temp
一句话总结:装饰器的本质也是一种运算符
举例1说明:
def decorator(func):
print("in decorator")
print("it's func:" + str(func))
print("out decorator")
return 996
@decorator
def main():
print("This is main()")
if __name__ == "__main__":
print(type(main))
print(main)
上面这段代码会依次打印:
in decorator
it's func:<function main at 0x037ED9C0>
out decorator
<class 'int'>
996
案例1理解:
按照说法先执行decorator(main),所以会先打印
in decorator
it's func:<function main at 0x037ED9C0>
out decorator
然后把main函数传进decorator函数,并且将返回值赋值给main,所以main就是996这个数字了。
二. 实际使用
我们使用装饰器的目的是为了简化代码的修改,比如我需要在所有的函数入口打印消息表示进入函数。假设原代码是这样的:
def funA():
while True:
pass
print("funA")
def funB():
raise Exception("my exception")
print("funB")
def funC():
a = 6
b = 3
c = 1
print(a + b + c)
不使用装饰器的做法是:
def funA():
print("in funA")
while True:
pass
print("funA")
def funB():
print("in funB")
raise Exception("my exception")
print("funB")
def funC():
print("in funC")
a = 6
b = 3
c = 1
print(a + b + c)
使用装饰器的做法是:
def decorator(fun):
def whatever():
print("in " + str(func))
fun()
return
return whatever
@decorator
def funA():
while True:
pass
print("funA")
@decorator
def funB():
raise Exception("my exception")
print("funB")
@decorator
def funC():
a = 6
b = 3
c = 1
print(a + b + c)
可以看到这样做能够避免散弹式修改,如果后期还需要在调用这些函数前后加一些操作,直接修改decorator函数即可。比如现在又需要在函数出口打印退出函数消息,修改decorator即可
def decorator(fun):
def whatever():
print("in " + str(func))
fun()
print("out " + str(func))
return
return whatever
这里引用装饰器时,相当于执行以下语句
temp = decorator(funC)
func = temp
也就是说func就等同于decorator里面的函数whatever了
三. 装饰器的进阶使用
以上你已经理解了装饰器语法糖的含义,也了解了装饰器的基本使用目的,下面就介绍一下更加复杂的用法
3.1 传参数1
被装饰的函数如何传参数到装饰器里面的函数呢?可以参考一下下面的例子:
def decorator(func):
def whatever(*sub_args, **sub_kwargs):
print("in sub")
func(*sub_args, **sub_kwargs)
print("out sub")
return
return whatever
@decorator
# @decorator: test = decorator(test)
def test(name, subname):
print(name + subname)
3.2 传参数2
被装饰的函数如何传参数到装饰器函数呢?可以参考一下下面的例子:
def decorator(param):
def real_decorator(func):
def whatever(*sub_args, **sub_kwargs):
print("in sub")
print(param)
func(*sub_args, **sub_kwargs)
print("out sub")
return
return whatever
return real_decorator
@decorator(param="param")
# 先执行decorator(param="param")返回一个函数real_decorator
# 再执行@real_decorator,相当于执行test = real_decorator(test)
def test(name, subname):
print(name + subname)
详解
名称后面加小括号表示调用,优先级高于装饰器语法糖,所以先执行调用,再进行装饰
@decorator(param="param")
def test(name, subname):
||
\/
test = decorator(param="param")(test)
||
\/
temp = decorator(param="param")
test = temp(test)
3.3 多重装饰器
def decorator1(func):
print('in decorator1')
def whatever1():
print('in whatever1')
return func()
return whatever1
def decorator2(func):
print('in decorator2')
def whatever2():
print('in whatever2')
return func()
return whatever2
@decorator1
@decorator2
def test():
print('test result')
test()
依次输出:
in decorator2
in decorator1
in whatever1
in whatever2
test result
详解:
test = decorator1(@decorator2
def test():)
||
\/
test = decorator1(decorator2(test))
3.4 让被装饰函数表示自己
不表示自己时:
def decorator(func):
def whatever(*sub_args, **sub_kwargs):
print("in sub")
func(*sub_args, **sub_kwargs)
print("out sub")
return
return whatever
@decorator
# @decorator: test = decorator(test)
def test(name, subname):
print(name + subname)
print(test)
打印结果:<function decorator.<locals>.whatever at 0x0147D9C0>
表示自己需要借助其他函数:
import functools
def decorator(func):
@functools.wraps(func)
def whatever(*sub_args, **sub_kwargs):
print("in sub")
func(*sub_args, **sub_kwargs)
print("out sub")
return
return whatever
@decorator
# @decorator: test = decorator(test)
def test(name, subname):
print(name + subname)
print(test)
打印结果:<function test at 0x00BDDC48>