什么是装饰器

一个装饰器就是一个函数,它接受一个函数作为参数并返回一个新的函数,简单的来说就是给一个函数增加额外的操作,并且可以复用。好处是 不直接入侵原有的代码逻辑,

装饰器的用途

  • 提供缓存/代理/上下文
  • 日志等等

    装饰器的方式

  • 不带参数装饰器

  • 带参数长势器: 其实就是引用了闭包概念 外套了一层函数
  • 类装饰器

实现一个函数运行装饰器
  1. import time
  2. from functools import wraps
  3. def decorator(func):
  4. @wraps(func) # 如果对函数元信息没有要求可以不添加
  5. def do(*args, **kwargs):
  6. start_tm = time.time()
  7. func()
  8. end_tm = time.time()
  9. print(f"函数运行时间{end_tm - start_tm}")
  10. return do
  11. def timeit(out='函数运行时间为:%.2fs'):
  12. def decorator(func):
  13. def do(*args, **kwargs):
  14. start_time = time.time()
  15. func()
  16. end_tm = time.time()
  17. print(out % (end_tm - start_time))
  18. return do
  19. return decorator
  20. @timeit('函数运行时间为:%.2fs --来自带参数的装饰器')
  21. def func():
  22. time.sleep(1)
  23. pass
  24. if __name__ == '__main__':
  25. func()

类装饰器

  1. 实现类 装饰器 主要是在类中实现call 函数,否者调用不起来
  1. class Timeit:
  2. def __init__(self, fun):
  3. self.fun = fun
  4. def __call__(self, *args, **kwargs):
  5. start_time = time.time()
  6. self.fun()
  7. end_tm = time.time()
  8. print(end_tm - start_time)
  9. @Timeit
  10. def func():
  11. time.sleep(1)
  12. pass
  13. if __name__ == '__main__':
  14. func()

总结:
- 装饰器是在运行的时候就加载的
- 多个装饰器 自上而下的启动【拨洋葱一样】
- 使用装饰器为了保持函数的元信息不被覆盖 通常使用wraps来装饰保留原信息
- 装饰器中有闭包的身影

实现一个缓存装饰器

  1. # 实现fib 装饰器缓存版本
  2. # 实现对 fib(n) 字典的 缓存计划
  3. # 自己实现的 装饰器 执行二次的确节约了时间,但是 如何做 第一次就进行cache?
  4. cache_dict = {}
  5. def cache(fun):
  6. def do(*args, **kwargs):
  7. n = args[0]
  8. if not n in cache_dict:
  9. num = fun(n)
  10. cache_dict[n] = num
  11. else:
  12. num = cache_dict[n]
  13. return num
  14. return do
  15. @cache
  16. def fib(n):
  17. a, b = 0, 1
  18. while n > 0:
  19. a, b = b, a + b
  20. n -= 1
  21. yield a
  22. import time
  23. class TiemTrace:
  24. def __init__(self, f):
  25. self.f = f
  26. print(f.__doc__)
  27. def __now(self):
  28. return time.time()
  29. def __enter__(self):
  30. self.start = self.__now()
  31. return self
  32. def __exit__(self, exc_type, exc_val, tb):
  33. self.end = self.__now()
  34. print('cost {}'.format(self.end - self.start))
  35. def __call__(self, n):
  36. start = self.__now()
  37. val = self.f(n)
  38. end = self.__now()
  39. print('{}, {}, {}, cost: {} seconds'.format(self.f.__name__, n , val, (end - start)))
  40. return val
  41. if __name__ == '__main__':
  42. start_tm = time.time()
  43. for i in fib(10):
  44. print(i)
  45. end_tm = time.time()
  46. print(end_tm - start_tm)
  47. start_tm = time.time()
  48. for i in fib(10):
  49. print(i)
  50. end_tm = time.time()
  51. print(end_tm - start_tm)
  52. with TiemTrace(fib) as f:
  53. for i in f(10):
  54. print(i)

AOP概念及作用

AOP 即面向切面编程,指扩展功能不修改源代码,将功能代码从业务逻辑代码中分离出来。
主要作用就是将类似于日志记录,性能统计,安全控制,事务处理,异常处理等重复性的代码块从业务逻辑代码中划分出来,对这些行为的分离。并且将它们独立到非知道业务逻辑的方法中,从而做到改变这些行为的时候不影响业务逻辑代码。

装饰器实现AOP

我们python中使用装饰器实现AOP。装饰器是一个很著名的设计模式,经常被用于有切面需求的场景,装饰器的作用就是为已经存在的对象添加额外的功能。