2一, 什么是装饰器
1,python 中装饰器可以理解为 AOP 编程, 有点类似 Spring 中的注解, 在不改变原函数或类的基础上, 对函数或类添加额外 (自己需求补充) 的功能.
2, 装饰器本质上是一个函数, 该函数用来处理其他函数, 它可以让其他函数在不需要修改代码的前提下增加额外的功能, 装饰器的返回值也是一个函数对象.
3, 有了装饰器, 我们就可以抽离出大量与函数功能本身无关的雷同代码并继续重用.
4, 比如我们要给每一个函数新增一个打印 logger 日志, 我们就可以使用装饰器, 在不修改原函数的前提下, 新增功能又能做到代码的解耦.
二, 装饰器的几个原则及学习装饰器必要的知识储备
1, 装饰器的几个原则
1. 不能修改被装饰的函数
2. 不能修改被装饰的函数的调用方式
2, 学习装饰器必要的知识
1. 函数的理解 不太熟悉的可以参考我之前写的文章 http://yst168.cn/article/article_detail/30/
2. 高阶函数 不太熟悉的可以参考我之前写的文章 http://yst168.cn/article/article_detail/31/
3. 函数的嵌套 不太熟悉的可以参考我之前写的文章 http://yst168.cn/article/article_detail/31/
三, 装饰器的演变过程
1, 定义一个装饰器(计算函数执行时间)
- import time
- def timer(func):
- def wrapper():
- start_time = time.time()
- res = func()
- end_time = time.time()
- print('程序运行时间:{0}'.format(end_time - start_time))
- return res
- return wrapper
2, 定义一个要执行的函数
- def foo():
- time.sleep(3)
- print('主函数')
3, 根据上面几个原则, 我们来调用函数 foo
- if __name__ == "__main__":
- # 1.timer 函数中传递函数 foo 进去
- # 2. 为了不改变函数的调用方式, 将 timer 函数的返回值 (函数) 赋值给变量 foo
- foo = timer(foo) # 前面 foo 是新定义的变量, timer 中的 foo 是上面定义的 foo 函数
- foo() # timer 是一个高阶函数, 返回的是一个函数
4, 解答上面的代码
1. 定义的装饰器是一个高阶函数, 被装饰的函数作为参数传递进去
2. 在满足装饰的原则下, 我们把高阶函数执行后重新赋值给 foo 函数
3.foo()函数的执行就没改变原有函数的调用方式
5, 使用装饰器 **@**
上面第四点中 2 和 3 步骤在 python 中直接使用 **@** 语法糖来处理
- @timer
- def bar():
- time.sleep(2)
- print('主函数')
- if __name__ == "__main__":
- bar()
四, 装饰器中传递参数
- import time
- def timer(func):
- def wrapper(*args, **kwargs):
- start_time = time.time()
- res = func(*args, **kwargs)
- end_time = time.time()
- print('执行时间:{0}'.format(end_time - start_time))
- return res
- return wrapper
- @timer
- def foo(name, gender):
- time.sleep(3)
- print(name)
- print(gender)
- if __name__ == "__main__":
- foo('张三', gender='男')
五, 使用类来作装饰器
创建一个数据库操的 log 的装饰器
1, 具体实现代码
- from functools import wraps
- from datetime import datetime
- # 创建一个类的装饰器
- class Log(object):
- def __init__(self, logfile='log.log'):
- self.logfile = logfile
- def __call__(self, func):
- @wraps(func)
- def wrapper(*args, **kwargs):
- self.writelog(*args, **kwargs)
- return func(*args, **kwargs)
- return wrapper
- # 把日志写到本地
- def writelog(self, *args, **kwargs):
- time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
- log_str = time + '操作人:{0[0]} 进行了[{0[1]}] 操作'.format(args)
- # 写入本地文件中
- with open(self.logfile, 'a', encoding='utf8') as file:
- file.write(log_str + '\n')
- @Log()
- def printLog(name, type):
- print('姓名:{0},type:{1}'.format(name, type))
- if __name__ == "__main__":
- printLog('张三', '查询')
- printLog('李四', '新增')
2, 执行结果(本地文件夹下多一个文件)
2018-06-24 10:47:40 操作人: 张三 进行了[查询] 操作
2018-06-24 10:47:40 操作人: 李四 进行了[新增] 操作
来源: https://juejin.im/post/5be136e96fb9a049fe349ba9