什么是装饰器

让其他函数在不需要做任何代码变动的前提下,增加额外的功能,装饰器的返回值也是一个函数对象。
装饰器的应用场景:比如插入日志,性能测试,事务处理,缓存等等场景。

装饰器的形成过程

如果我想测试某个函数的执行时间

  1. import time
  2. def func1():
  3. print('in func1')
  4. def timer(func):
  5. def inner():
  6. start = time.time()
  7. func()
  8. print(time.time() - start)
  9. return inner
  10. func1 = timer(func1)
  11. func1()

Python
Copy
但是如果有多个函数,我都想让你测试他们的执行时间,你每次是不是都得 func1 = timer(func1)? 这样还是有点麻烦,因为这些函数的函数名可能是不相同,有 func1,func2,graph, 等等,所以更简单的方法,python 给你提供了,那就是语法糖。

  1. import time
  2. def timer(func):
  3. def inner():
  4. start = time.time()
  5. func()
  6. print(time.time() - start)
  7. return inner
  8. @timer
  9. def func1():
  10. time.sleep(1)
  11. print('in func1')
  12. func1()

Python
Copy
装饰一个带参数的函数

  1. import time
  2. def timer(func):
  3. def inner(a):
  4. start = time.time()
  5. func(a)
  6. print(time.time() - start)
  7. return inner
  8. @timer
  9. def func1(a):
  10. time.sleep(1)
  11. print(a)
  12. func1('hello world')

Python
Copy
装饰一个带各种参数的函数

  1. import time
  2. def timer(func):
  3. def inner(*args,**kwargs):
  4. start = time.time()
  5. func(args,kwargs)
  6. print(time.time() - start)
  7. return inner
  8. @timer
  9. def func1(*args,**kwargs):
  10. print(args,kwargs)
  11. func1('hello world','abc',123,432)

Python
Copy
查看函数的相关信息,在加上装饰器后就失效了

  1. def index():
  2. '''这是一条注释信息'''
  3. print('from index')
  4. print(index.__doc__) # 查看函数注释
  5. print(index.__name__) # 查看函数名称

Python
Copy
导入 wraps 装饰器

  1. from functools import wraps
  2. def deco(func):
  3. @wraps(func)
  4. def wrapper(*args,**kwargs):
  5. return func(*args,**kwargs)
  6. return wrapper
  7. @deco
  8. def index():
  9. '''这是一条注释信息'''
  10. print('from index')
  11. print(index.__doc__) # 查看函数注释
  12. print(index.__name__) # 查看函数名称

Python
Copy

开放封闭原则

一句话,软件实体应该是可扩展但是不可修改的。

  • 对于扩展是开放的
  • 对于修改是封闭的

装饰器完美的遵循了这个开放封闭原则

装饰器的主要功能和固定结构

  1. def timer(func):
  2. def inner(*args,**kwargs):
  3. '''执行函数之前要做的'''
  4. re = func(*args,**kwargs)
  5. '''执行函数之后要做的'''
  6. return re
  7. return inner
  8. # 下面是加上wraps的固定结构
  9. from functools import wraps
  10. def timer(func):
  11. @wraps(func)
  12. def wrapper(*args,**kwargs)
  13. return func(*args,**kwargs)
  14. return wrapper

Python
Copy

带参数的装饰器

加上一个 outer 函数,可以携带一个 flag 的值,然后控制装饰器是否生效

  1. def outer(flag):
  2. def timer(func):
  3. def inner(*args,**kwargs):
  4. if flag:
  5. print('函数开始执行')
  6. re = func(*args,**kwargs)
  7. if flag:
  8. print('函数执行完毕')
  9. return re
  10. return inner
  11. return timer
  12. @outer(True)
  13. def func():
  14. print('test')
  15. func()

Python
Copy

多个装饰器装饰一个函数

  1. def wrapper1(func):
  2. def inner():
  3. print('第一个装饰器,在程序运行之前')
  4. func()
  5. print('第一个装饰器,在程序运行之后')
  6. return inner
  7. def wrapper2(func):
  8. def inner():
  9. print('第二个装饰器,在程序运行之前')
  10. func()
  11. print('第二个装饰器,在程序运行之后')
  12. return inner
  13. @wrapper1
  14. @wrapper2
  15. def f():
  16. print('Hello')
  17. f()