搞定三大神器之 Python 装饰器
学会 Python 装饰器
装饰器,几乎各大Python框架中都能看到它的身影,足以表明它的价值!它有动态改变函数或类功能的魔力!
本专题的目录:
- 学会 Python 装饰器
- 1 什么是装饰器
- 2 装饰器的结构
- 3 为什么要这样
- 4 装饰一个函数
- 5 装饰一个类
- 6 装饰器层叠
- 7 温馨提醒
- 总结
1 什么是装饰器
对于受到封装的原函数比如f
来说,装饰器能够在f
函数执行前或者执行后分别运行一些代码。
2 装饰器的结构
装饰器也是一个函数,它装饰原函数f
或类cls
后,再返回一个函数g
装饰一个函数:
def decorator(f):
# 定义要返回的函数
def g():
print('函数f执行前的动作')
f()
print('函数f执行后的动作')
return g
装饰一个类:
def decorator(cls):
# 定义要返回的函数
def g():
print('类cls执行前的动作')
f()
print('类cls执行后的动作')
return g
使用装饰器很简单,@+自定义装饰器 装饰要想装饰的函数。
3 为什么要这样
要想理解装饰器为什么要有这种结构,要首先想明白装饰器的目标是什么。
它的价值在于为原函数f
增加一些行为,前提必须不能破坏函数f
,所以肯定不能改变f的内部结构,所以只能在调用f前后定义一些行为。
同时,装饰器函数decorator
返回值又是什么?你可以思考下,返回一个函数是再好不过的了,它包装了原函数f
.
4 装饰一个函数
printStar函数接收一个函数f
,返回值也是一个函数,所以满足装饰器的结构要求,所以printStar是一个装饰器。
def printStar(f):
def g():
print('*'*20)
f()
print('*'*20)
return g
printStar装饰器实现f函数执行前、后各打印20个*字符。
使用printStar:
@printStar
def f():
print('hello world')
调用:
if __name__ == '__main__':
### 改变函数功能
f()
打印结果:
********************
hello world
********************
可以很方便的装饰要想装饰的其他函数,如下:
@printStar
def g():
print('welcome to Python')
5 装饰一个类
除了可以装饰函数f外,还可以装饰类cls,两者原理都是一样的。
下面给出一个装饰器实现单例模式的例子,所谓单例就是类只有唯一实例,不能有第二个。
def singleton(cls):
instance = {}
def get_instance(*args, **kwargs):
if cls not in instance:
instance[cls] = cls(*args, **kwargs)
return instance[cls]
return get_instance
定义字典instance
,键值对分别为类和实例,这样确保只cls()一次。
使用装饰器singleton修饰类:
@singleton
class CorePoint:
pass
测试:
if __name__ == '__main__':
### 改变类的功能
c1 = CorePoint()
c2 = CorePoint()
print(c1 is c2) # True
6 装饰器层叠
上面原函数f不仅能被一个装饰器修饰,还能被n多个装饰器修饰。
下面再定义一个装饰器printLine,被修饰函数执行前后打印20个 -
def printLine(f):
def g():
print('-'*20)
f()
print('-'*20)
return g
使用上文定义好的printStar
和printLine
同时装饰函数f:
@printStar
@printLine
def f():
print('hello world')
此时再调用函数f:
if __name__ == '__main__':
### 改变函数功能
f()
打印结果:
********************
--------------------
hello world
--------------------
********************
f被装饰后,先打印*,再打印 -
层叠多一层,原函数f就变强大一层。使用装饰器,还能实现功能抽离,进一步实现松耦合。
7 温馨提醒
打印原函数f的名字__name__
,结果为f
In [1]: def f():
...: pass
In [4]: f.__name__
Out[4]: 'f'
但是,被装饰后函数名字f变为g,这不是我们希望的!
@printStar
def f():
pass
f()
f.__name__ # g
Python提供的解决方案:使用functools模块中的wraps
装饰器:
from functools import wraps
def printStar(f):
@wraps(f)
def g():
print('*'*20)
f()
print('*'*20)
return g
此时再打印被装饰后f的名字,显示f,正常!
总结
- 学会 Python 装饰器
- 1 什么是装饰器
- 2 装饰器的结构
- 3 为什么要这样
- 4 装饰一个函数
- 5 装饰一个类
- 6 装饰器层叠
- 7 温馨提醒
- 总结
- 编程成为面向未来的基本能力?
- null或空值的判断处理
- 前端知识小结
- 除了比特币,区块链技术能做的还有很多
- Progressive Web Apps入门
- IDEA入门级使用教程
- 掌握Docker命令-Docker for Web Developers(4)
- InfoPath中repeating section中赋值操作
- 百布(baibu.la)完成1.65亿B+轮融资
- 八大排序算法总结与java实现
- Angular企业级开发(5)-项目框架搭建
- 如何让nginx显示文件夹目录
- Facebook Graph API(2)--读取数据之picture
- 使用Dockerfile构建镜像-Docker for Web Developers(5)
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- linux系统 java环境变量的配置办法
- 在Linux中怎么轻松删除源安装的软件包
- Linux中selinux基础配置教程详解
- 怎么禁用 Ubuntu 服务器中终端欢迎消息中的广告
- Laravel5.1 框架响应基本用法实例分析
- 在Linux中怎么一次重命名多个文件详解
- python调用私有属性的方法总结
- PHP+MySQL实现在线测试答题实例
- Python异常处理机制结构实例解析
- PHP字符串与数组处理函数用法小结
- 详解Flask前后端分离项目案例
- Laravel5.1 框架表单验证操作实例详解
- 通过实例了解Python异常处理机制底层实现
- header函数设置响应头解决php跨域问题实例详解
- Linux采用双网卡bond、起子接口的方式