装饰器

什么是装饰器

装饰器遵循在不改变装饰对象(函数)原有的“调用方式”和“内部代码”的情况下给被装饰对象添加新的功能。装饰器的原则是对扩展开放,对修改封闭

为什么要用装饰器

在项目完成后,需要在原有的基础上有新的需求或变化时,可以对现有代码进行扩展,以适应新的情况这就用到了装饰器

装饰器的实现

简易版本装饰器

  1. import time
  2. def index():
  3. time.sleep(3) # 5.停止3秒
  4. print("from function index") # 6.输出
  5. # 要求:给index函数增加了一个统计执行时间的功能
  6. def outer(func):
  7. def get_time(): # 2.把index函数名绑定给func
  8. start_time = time.time() # 3.开始计时
  9. func() # 4.调用index函数
  10. end_time = time.time() # 计时结束
  11. print(end_time - start_time) # index()执行的时间
  12. return get_time
  13. index = outer(index) # 1.通过调用get_time函数把index函数名当做参数传进去
  14. index() # 可以看做似调用的index其实调用的是get_time
  15. # from function index
  16. # 3.0043959617614746
  17. print(index) # 全局名称空间中的index指向的是get_time函数体代码
  18. # <function outer.<locals>.get_time at 0x7fcf403edf28>

进阶版本装饰器

  1. # 解决不同函数,需要传的参数个数问题
  2. def outer(func_name):
  3. def get_time(*args, **kwargs):
  4. start_time = time.time()
  5. func_name(*args, **kwargs)
  6. end_time = time.time()
  7. print(end_time - start_time)
  8. return get_time

完整版本装饰器

  1. # 解决无法返回值问题
  2. def outer(func_name):
  3. def get_time(*args, **kwargs):
  4. start_time = time.time()
  5. res = func_name(*args, **kwargs)
  6. end_time = time.time()
  7. print(end_time - start_time)
  8. return res
  9. return get_time

装饰器模板(重要)

  1. def outer(func_name):
  2. def inner(*arg, **wargs):
  3. print("修改前的操作")
  4. res = func_name(*arg, **kwargs)
  5. print("修改后的操作")
  6. return res
  7. return inner

装饰器语法糖

  1. # 仅仅是让代码编写的更加好看、简洁!!!
  2. def outer(func_name):
  3. def inner(*arg, **kwargs):
  4. print("修改前的操作")
  5. res = func_name(*arg, **kwargs)
  6. print("修改后的操作")
  7. return res
  8. return inner
  9. @outer # 等价于 index = outer(index)
  10. def index():
  11. print("from function index")
  12. index()

装饰器“修复技术”

  1. # 做到比真的还要真 但是本质其实没有变
  2. from functools import wraps
  3. def outer(func_name):
  4. @wraps(func_name)
  5. def inner(*arg, **kwargs):
  6. print("修改前的操作")
  7. res = func_name(*arg, **kwargs)
  8. print("修改后的操作")
  9. return res
  10. return inner
  11. @outer
  12. def index():
  13. """这是注释"""
  14. print('from function index')
  15. help(index) # help可以查看指定函数的注释信息
  16. index()
  17. # 修改前的操作
  18. # from function index
  19. # 修改后的操作

多层装饰器

  1. """语法糖会将紧挨着的被装饰对象的名字当做参数自动传入装饰器函数中"""
  2. def outer_1(func_1):
  3. print('加载了outer_1')
  4. def inner_1(*args, **kwargs):
  5. print('执行了inner_1')
  6. res1 = func_1(*args, **kwargs)
  7. return res1
  8. return inner_1
  9. def outer_2(func_2):
  10. print('加载了outer_2')
  11. def inner_2(*args, **kwargs):
  12. print('执行了inner_2')
  13. res2 = func_2(*args, **kwargs)
  14. return res2
  15. return inner_2
  16. def outer_3(func3):
  17. print('加载了outer_3')
  18. def inner_3(*args, **kwargs):
  19. print('执行了inner_3')
  20. res3 = func3(*args, **kwargs)
  21. return res3
  22. return inner_3
  23. @outer_1 # index = outer_1(index)
  24. @outer_2 # index = outer_2(index)
  25. @outer_3 # index = outer_1(outer_2(outer_3(index)))
  26. def index():
  27. print('from function index')
  28. index()
  29. # 加载了outer_3
  30. # 加载了outer_2
  31. # 加载了outer_1
  32. # 执行了inner_1
  33. # 执行了inner_2
  34. # 执行了inner_3
  35. # from function index

有参装饰器

  1. def outer(source_data): # 用来给装饰器传递值
  2. def login_auth(func_name): # 不能动,只能接收一个被装饰对象名字
  3. def inner(*args, **kwargs): # 不能动,是专门用来给被装饰的对象传参的
  4. if source_data == '1':
  5. print('操作1')
  6. elif source_data == '2':
  7. print('操作2')
  8. elif source_data == '3':
  9. print('操作3')
  10. else:
  11. print('其他操作')
  12. res = func_name(*args, **kwargs)
  13. return res
  14. return inner
  15. return login_auth
  16. num = input("输入你要操作的方式:")
  17. @outer(num)
  18. def index():
  19. print('from function index')
  20. index()

类作为装饰器

  1. class Decorator(object):
  2. def __init__(self, f):
  3. self.f = f
  4. def __call__(self):
  5. print("进入", self.f.__name__)
  6. self.f()
  7. print("退出", self.f.__name__)
  8. @Decorator
  9. def func():
  10. print("执行 func1()")
  11. func()
  12. # 进入 func
  13. # 执行 func1()
  14. # 退出 func

对象作为装饰器

  1. class Decorator:
  2. def __init__(self, arg1, arg2):
  3. print('执行类Decorator的__init__()方法')
  4. self.arg1 = arg1
  5. self.arg2 = arg2
  6. def __call__(self, f):
  7. print('执行类Decorator的__call__()方法')
  8. def wrap(*args):
  9. print('执行wrap()')
  10. print('装饰器参数:', self.arg1, self.arg2)
  11. print('执行' + f.__name__ + '()')
  12. f(*args)
  13. print(f.__name__ + '()执行完毕')
  14. return wrap
  15. @Decorator('Hello', 'World')
  16. def example(a1, a2, a3):
  17. print('传入example()的参数:', a1, a2, a3)
  18. print('装饰完毕')
  19. print('准备调用example()')
  20. example('Wish', 'Happy', 'EveryDay')
  21. print('测试代码执行完毕')

这里的参考文章:https://zhuanlan.zhihu.com/p/93846887