python当中的装饰器
1.装饰器
首先我们来说一下一个软件的设计原则:开闭原则,又被称为开发封闭原则,你的代码对功能的扩展是开放的,你的程序对修改源代码是封闭的.这样的软件设计思路可以更好的维护和开发.
开放:对功能扩展开放
封闭:对修改代码封闭
接下来我们看装饰器.首先我们先模拟一下女娲造人.
- def create():
- print('女娲很厉害,捏个泥人吹口气就成了人')
- create_people()
现在我们让这个函数加个浇水功能.
- def create():
- print('浇水')
- print('女娲很厉害,捏个泥人吹口气就成了人')
- create_people()
但是,现在就违反了开闭原则,如果每次要添加新功能,那这样就等于是修改了源代码.因为开闭原则对修改是封闭的,那怎么办,我们可以这样做
- def water():
- print('先浇水')
- create()
- water()
这样做的问题是.函数写好了,重新创建了这个函数,在这之前访问过这个函数的人必须要修改代码来访问新的函数water(),所以现在就用到了装饰器,装饰器的作用就是在不修改原有代码的基础上,给函数扩展功能
- def create_people():
- print('女娲很厉害随随便便就造人')
- def water(fn):
- def inner():
- print('浇浇水')
- fn()
- print('施肥')
- return inner
- # # create_people() # 这个就不行了.
- # warter() # 访问浇水就好了
- # func = water(create_people)
- # func() # 有人问了. 下游访问的不不依然是func么, 不不还是要改么?
- create_people = water(create_people)
- create_people() # 这回就好了吧
说一下执行流程:
结论: 我们使用water函数把create_people给包装了一下. 在不修改create_people的前提下.
完成了对create_people函数的功能添加
下面我们给出装饰器的完整模型代码
- def wrapper(fn): # fn是目标函数
- def inner(*args,**kwargs): # 为了目标函数的传参
- '''这里是执行函数前的内容'''
- ret = fn(*args,**kwargs) # 调用目标函数,ret是目标函数的返回值
- '''这里是执行目标函数后的内容
- return ret # 把目标函数的返回值返回.保证函数正常的结束
- return inner
- @wrapper # 这里是语法糖
- def func():
- print('我是目标函数")
- func() # 调用目标函数
二.带参数的装饰器
注意: 咱们之前的写法是@wrapper 其中wrapper是一个函数. 那么也就是说. 如果我能让wrapper这里换成个函数就行了了. wrapper(True)返回的结果是wrapper也是⼀一个函数啊. 刚刚
好和前面的@组合成一个@wrapper. 依然还是原来那个装饰器. 只不过这里套了3层. 但你要
能看懂. 其实还是原来那个装饰器@wrapper
执行步骤:
先执行wrapper(True) 然后再@返回值. 返回值恰好是wrapper. 结果就是@wrapper
下面是装饰器传参的通用写法
- def wrapper_out(flag):
- def wrapper(fn):
- def inner(*args,**kwargs):
- if flag == True:
- '''执行目标函数前的位置'''
- ret = fn(*args,**kwargs)
- '''执行目标函数后的位置'''
- return ret
- else:
- ret = fn(*args,**args)
- return ret
- return inner
- return wrapper
- @wrapper_out(True)
- def func():
- print('这里是目标函数')
- func()
三.多个装饰器装饰同一个函数
- def wrapper1(fn):
- def inner(*args,**kwargs):
- print('111')
- ret = fn(*args,**kwargs)
- print('222')
- return inner
- def wrapper2(fn):
- def inner(*args,**kwargs):
- print('333')
- ret = fn(*args,**kwargs)
- print('444')
- return inner
- def wrapper3(fn):
- def inner(*args,**kwargs):
- print('555')
- ret = fn(*args,**kwargs)
- print('666')
- return inner
- @wrapper1
- @wrapper2
- @wrapper3
- def eat():
- print('我想吃水果')
- eat()
执行顺序: 首先@wrapper1装饰起来. 然后获取到⼀个新函数是wrapper1中的inner. 然后执行@wrapper2.这个时候. wrapper2装饰的就是wrapper1中的inner了了. 所以. 执行顺序就像:第⼆层装饰器前(第⼀层装饰器前(目标)第一层装饰器后)第二层装饰器后. 程序从左到右执行起来. 就是我们看到的结果
四. 使用wraps装饰函数保留函数的原名称
1.wraps
装饰器装饰的函数名字会变为inner,为了让装饰的函数名还原,我们用到了@wraps,这样打印出的函数名就还是原来的函数名了, 要引入functools模块
- from functools import wraps # 可以改变一个函数的名字, 注释...
- def wrapper(fn):
- @wraps(fn) # 把inner的名字改变成原来的func
- def inner(*args, **kwargs):
- print("前")
- ret = fn(*args, **kwargs)
- print("后")
- return ret
- return inner
- @wrapper # func = wrapper(func)
- def func():
- print('哈哈哈')
- print(func.__name__) # func
python当中的装饰器的更多相关文章
- 面向切面编程AOP——加锁、cache、logging、trace、同步等这些较通用的操作,如果都写一个类,则每个用到这些功能的类使用多继承非常难看,AOP就是解决这个问题的,python AOP就是装饰器
面向切面编程(AOP)是一种编程思想,与OOP并不矛盾,只是它们的关注点相同.面向对象的目的在于抽象和管理,而面向切面的目的在于解耦和复用. 举两个大家都接触过的AOP的例子: 1)java中myba ...
- python高级之装饰器
python高级之装饰器 本节内容 高阶函数 嵌套函数及闭包 装饰器 装饰器带参数 装饰器的嵌套 functools.wraps模块 递归函数被装饰 1.高阶函数 高阶函数的定义: 满足下面两个条件之 ...
- [python基础]关于装饰器
在面试的时候,被问到装饰器,在用的最多的时候就@classmethod ,@staticmethod,开口胡乱回答想这和C#的static public 关键字是不是一样的,等面试回来一看,哇,原来是 ...
- python笔记 - day4-之装饰器
python笔记 - day4-之装饰器 需求: 给f1~f100增加个log: def outer(): #定义增加的log print("log") ...
- Python深入05 装饰器
作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! 装饰器(decorator)是一种高级Python语法.装饰器可以对一个函数.方法 ...
- Day04 - Python 迭代器、装饰器、软件开发规范
1. 列表生成式 实现对列表中每个数值都加一 第一种,使用for循环,取列表中的值,值加一后,添加到一空列表中,并将新列表赋值给原列表 >>> a = [0, 1, 2, 3, 4, ...
- Noah的学习笔记之Python篇:装饰器
Noah的学习笔记之Python篇: 1.装饰器 2.函数“可变长参数” 3.命令行解析 注:本文全原创,作者:Noah Zhang (http://www.cnblogs.com/noahzn/) ...
- 第二篇:python高级之装饰器
python高级之装饰器 python高级之装饰器 本节内容 高阶函数 嵌套函数及闭包 装饰器 装饰器带参数 装饰器的嵌套 functools.wraps模块 递归函数被装饰 1.高阶函数 高阶函 ...
- 简单说明Python中的装饰器的用法
简单说明Python中的装饰器的用法 这篇文章主要简单说明了Python中的装饰器的用法,装饰器在Python的进阶学习中非常重要,示例代码基于Python2.x,需要的朋友可以参考下 装饰器对与 ...
随机推荐
- np的归纳总结
1. np.sqrt(input) # 求数的开方 import numpy as np print(np.sqrt(2)) 2. np.square(3) # 求数的平方 import n ...
- NotePad++替换行前、行后空格,替换空行
用 Notepad++ 打开,把每一个将要放在表中单元格的内容放一行(注: ^ 代表行首 $ 代表行尾) 去除行尾空格和空白行:按CTRL+H 选择正则表达式– 查找目标:\s+$ 替换为空 去除行首 ...
- Canvas.Pixels 实例:判断一点是否在区域中
The Windows 3.1 and Windows 95 GDI heap is limited in regards to scan converting large and complex r ...
- iOS load和initialize的区别
可能有些还不清楚load和initialize的区别,下面简单说一下: 首先说一下 + initialize 方法:苹果官方对这个方法有这样的一段描述:这个方法会在 第一次初始化这个类之前 被调用,我 ...
- 把二叉搜索树转化成更大的树 · Convert BST to Greater Tree
[抄题]: 给定二叉搜索树(BST),将其转换为更大的树,使原始BST上每个节点的值都更改为在原始树中大于等于该节点值的节点值之和(包括该节点). Given a binary search Tree ...
- 23-吝啬的国度(vector+深搜)
吝啬的国度 时间限制:1000 ms | 内存限制:65535 KB 难度:3 描述 在一个吝啬的国度里有N个城市,这N个城市间只有N-1条路把这个N个城市连接起来.现在,Tom在第S号城市, ...
- Docs命令大全 备用
#1 一: net use \\ip\ipc$ " " /user:" " 建立IPC空链接 net use \\ip\ipc$ "密码" ...
- Yii2 windows 安装步骤
安装 Yii2 高级版应用 基础版可以看官方文档 今天安装了YII2高级版应用 写下步骤 留个记号,以备查询! 在 Windows 中,你首先需要下载并运行 Composer-Setup.exe 查看 ...
- ajax数据流传参
- mysql5.7文件无法导入数据库的解决方案
一般是因为my.ini的“secure-file-priv”的设置导致loaddata失败,网上查了许多资料,大部分都是要求注释掉my.ini的: secure-file-priv="C:/ ...