语法

@文件名

  1. def show(fn):
  2. def temp(x,y):
  3. print("===========")
  4. z = fn(x,y)
  5. return z
  6. return temp
  7. def myadd(a,b):
  8. return a+b
  9. def mysubstract(a,b):
  10. return a-b
  11. def mymulitply(a,b):
  12. return a*b
  13. def mydivide(a,b):
  14. return a/b
  15. add = show(myadd)
  16. print(add(3,4))
  17. substract = show(mysubstract)
  18. print(substract(10,3))

优化使用@show 等价于 函数实际名=修饰器函数名(函数实际名)

  1. def show(fn):
  2. def temp(x,y):
  3. print("===========")
  4. return fn(x,y)
  5. return temp
  6. @show #myadd = show(myadd)
  7. def myadd(a,b):
  8. return a+b
  9. @show
  10. def mysubstract(a,b):
  11. return a-b
  12. @show
  13. def mymulitply(a,b):
  14. return a*b
  15. @show
  16. def mydivide(a,b):
  17. return a/b

改进能适应不同格式的参数

在执行功能函数前把通用的功能或者要对函数参数进行的处理放到装饰器中去进行,常见的例如输出logging

  1. def funx(*args,**kwargs): #args 收集关键字 #kwargs 收集关键字参数(字典等)
  2. print(args,kwargs)
  3. print(funx(1)) >>(1,)
  4. print(funx(6,4,6,刘能=183283231123)) >>(6,4,6) {"刘能":"183283231123"}
  5. def decorator(function):
  6. def wrapper(*args,**kwargs):
  7. print("=====开始======")
  8. print(list(args)[0]) #元组转化为列表进行处理
  9. x=function(*args,**kwargs)
  10. return x
  11. return wrapper
  12. @decorator
  13. def myadd(a,b,c):
  14. return a+b+c
  15. @decorator
  16. def mysubstract(a,b,c):
  17. return a-b-c
  18. @decorator
  19. def mymulitply(a,b):
  20. return a*b
  21. @decorator
  22. def mydivide(a,b):
  23. return a/b
  24. print(myadd(3,4,3))
  25. print(mysubstract(10,6,2))
  26. print(mymulitply(10,6))
  27. print(mydivide(10,2))

装饰器会修改原方法的namedoc,理论上我们不允许修改它,可以通过functools的wraps来实现

  1. from functools import wraps
  2. def log(flag):
  3. def decorate(func):
  4. @wraps(func)
  5. def _wrap(*args,**kwargs):
  6. try:
  7. if flag:
  8. func(*args,**kwargs)
  9. print('name ',func.__name__)
  10. except Exception as e:
  11. print(e.args)
  12. return _wrap
  13. return decorate
  14. @log(True)
  15. def sum(a,b,c):
  16. return a+b+c
  17. x = sum(1,2,3)
  18. print(sum) #打印sum的内存地址
  19. print(sum.__name__) #打印sum的函数名
  20. print(x)

有参装饰器

如何传入一个参数到装饰器中,装饰器中不允许直接传参数进入,所以我们一般采用的方法是在无参装饰器外在包裹一层函数,把参数传进去

  1. from functools import wraps
  2. def get_param(x):
  3. def decorate(func):
  4. @wraps(func)
  5. def wrapper(*args,**kwargs):
  6. if x =="a":
  7. print('111111')
  8. elif x = 'b':
  9. print('222222222')
  10. res = func(*args,**kwargs)
  11. print('the func end')
  12. return res
  13. return wrappers
  14. return decorate
  15. @get_param('a') #decorate = get_param('a') @decorate
  16. def func():
  17. print('3333333333333')
  18. >>>>
  19. print('11111111')
  20. print('3333333333')
  21. print('the func end')

多个装饰器执行顺序

如果一个函数上有多个装饰器,其执行顺序是按照自下而上的顺序执行的,也就是最里面的先执行,再依次往上去执行,其内存调用类似于堆栈,先进后出,举例如下

  1. def out1(function1):
  2. def wrapper1(*args,**kwargs):
  3. print("=====wrapper1 开始======")
  4. x=function1(*args,**kwargs)
  5. print("=====wrapper1 结束======")
  6. return x
  7. return wrapper1
  8. def out2(function2):
  9. def wrapper2(*args,**kwargs):
  10. print("=====wrapper2 开始======")
  11. x=function(*args,**kwargs)
  12. print("=====wrapper2 结束======")
  13. return x
  14. return wrapper2
  15. def out3(function3):
  16. def wrapper3(*args,**kwargs):
  17. print("=====wrapper3 开始======")
  18. x=function3(*args,**kwargs)
  19. print("=====wrapper3 结束======")
  20. return x
  21. return wrapper3
  22. @out3 # func = out3(out2.wrapper2) return func = out3.wrapper3
  23. @out2 # func = out2(out1.wrapper1) return func = out2.wrapper2
  24. @out1 # func = out1(func) return func = out1.wrapper1
  25. def func():
  26. print('111111111')
  27. func()
  28. >>>>
  29. #可以看到func被传递给了out3,即最后home指向了out3.wrapper3
  30. #调用out3.wrapper3的function其实是out2.wrapper2
  31. #调用out2.wrapper2的function其实是out1.wrapper1
  32. print("=====wrapper3 开始======")
  33. print("=====wrapper2 开始======")
  34. print("=====wrapper1 开始======")
  35. print('11111111111')
  36. print("=====wrapper1 结束======")
  37. print("=====wrapper2 结束======")
  38. print("=====wrapper3 结束======")