Noah的学习笔记之Python篇:装饰器
Noah的学习笔记之Python篇:
1.装饰器
2.函数“可变长参数”
3.命令行解析
注:本文全原创,作者:Noah Zhang (http://www.cnblogs.com/noahzn/)
年前工作事务比较繁琐,我只能用零碎的时间继续学习Python,决定开一个系列的博文,作为自己深入学习Python的记录吧。名字也取好了,就叫《ZMAN的学习笔记之Python篇》~开篇是关于装饰器的,春节假期码的字哈哈~就让我们开始吧!
本文的例子都是自己想的,如果不是很合适,请大家提出宝贵意见哈~谢谢啦!
一、为什么要用“装饰器”
比如我们写了如下一段代码:
# 打印0~99 def func():for i in range(100):print(i)
我们想要监测执行这个函数花费了多少时间,于是我们将这个函数改成了这样:
import time# 打印0~99 def func():start = time.time()for i in range(100):print(i)end = time.time()print("耗时:%.4f" % (end - start))
虽然达到了目的,但是我们却改变了原有的函数,而且如果有几十个不同的函数,都这样改动一下,工作量也是非常大的。
使用了“装饰器”后,就能在不修改原函数的前提下,达到相同的功能。
二、什么是“装饰器”
在Python中,函数是“对象”,而装饰器是函数,它的作用就是对已经存在的函数进行装饰。Python中的“装饰器”可以很好地解决那些有“面向切面编程”需求的问题。
请看例子:
def deco(ex):print('func函数被调用前')ex()print('func函数被调用后')return exdef func():print('func函数被调用')func = deco(func)>>> func函数被调用前 func函数被调用 func函数被调用后
我写了两个函数,将函数func作为参数传入deco函数,并将返回值赋给func变量。我们可以看成是func函数经过了deco的装饰~
而这就是装饰器的概念了:装饰器可以说是封装器,让我们在被装饰的函数之前或之后执行一些代码,而不必修改函数本身。利用这点,我们可以做出许多酷炫的功能~
三、写第一个“装饰器”
刚才我介绍了装饰器的概念,但这是一个“手工”的装饰器,并没有用到Python的装饰器语法,实际上,装饰器语法非常简单,看例子:
def deco(ex):def _deco():print('func函数被调用前')ex()print('func函数被调用后')return _deco@deco def func():print('func函数被调用')#return('OK') func()>>> func函数被调用前 func函数被调用 func函数被调用后
大家可以看到,我在定义函数func的上一行,加了一句“@deco”,这就是装饰器语法了,这样写了之后,能确保每次调用func函数都被deco函数装饰,是不是非常简单呀~~
四、让被装饰函数带上确定的参数
如果被装饰函数带可以确定的参数,需要像下面这样对装饰器函数进行修改:
def deco(ex):def _deco(a, b):print('%s函数被调用前' % ex.__name__)c = ex(a, b)print('%s函数被调用后,结果为:%s' % (ex.__name__, c))return _deco@deco def func(a, b):print('func函数被调用,传入%s,%s' % (a, b))return a+bfunc(1, 2)>>> func函数被调用前 func函数被调用,传入1,2 func函数被调用后,结果为:3
这个例子的装饰器实现了:打印传入函数的名字、打印两个数字相加结果的功能。我们在原先的deco函数内又定义了一个函数_deco用来接收func函数中的参数。
五、让被装饰函数带上不确定的参数
def deco(ex):def _deco(*args, **kwargs):print('%s函数被调用前' % ex.__name__)c = ex(*args, **kwargs)print('%s函数被调用后,结果为%s' % (ex.__name__, c))return _deco@deco def func(a, b):print('func函数被调用,传入%s,%s' % (a, b))return a+b@deco def func2(a, b, c):print('func2函数被调用,传入%s,%s,%s' % (a, b, c))return a+b+c func(1, 2) func2(1, 2, 3)>>> func函数被调用前 func函数被调用,传入1,2 func函数被调用后,结果为3 func2函数被调用前 func2函数被调用,传入1,2,3 func2函数被调用后,结果为6
简单修改我们的代码,使用*args, **kwargs来捕捉不定量的传参,便实现了多个参数的求和。
六、让装饰器带上参数
def deco(ex):def _deco(func):def _deco2():print('%s函数被调用前,传入参数为:%s' % (func.__name__, ex))func()print('%s函数被调用后' % func.__name__)return _deco2return _deco@deco('parameter1') def func():print('func函数被调用')func()>>> func函数被调用前,传入参数为:parameter1 func函数被调用 func函数被调用后
如果要让装饰器带上参数,我们要在装饰器函数内部再多定义一层函数,用来接收装饰器的参数~大家可不要搞混了装饰器参数和函数的参数哟~
七、来个任性的:装饰器和被装饰函数都带参数
def deco(ex):def _deco(func):def _deco2(c, d):print('%s函数被调用前,装饰器参数为:%s' % (func.__name__, ex))x = func(c, d)if x > 3:x = x-exelse:x = x+exprint('%s函数被调用后,计算结果为:%d\n' % (func.__name__, x))return _deco2return _deco@deco(3) def func(a, b):print('func函数执行结果为:%s' % int(a+b))return(a+b)func(3, 4) func(1, 2)>>> func函数被调用前,装饰器参数为:3 func函数执行结果为:7 func函数被调用后,计算结果为:4func函数被调用前,装饰器参数为:3 func函数执行结果为:3 func函数被调用后,计算结果为:6
最初的func函数只是实现两个数字的相加,经过装饰后实现了对func返回的和的大小进行了分支处理:如果“两数的和大于3”,最后结果为“两数的和减去3”,否则最后结果为“两数的和加上3”。我在这个例子中使用的是“确定”的参数,大家可以自己更改哦~
八、同时使用多个装饰器
之前的例子都是只用了一个装饰器,我们当然可以装饰多次啦~
def deco1(ex):def _deco1(string):print('deco1被调用前')string = ex(string)if 'hello' in string:string = "You are my old friend."else:string = "You are my new friend."print('deco1被调用后,%s\n' % string)return stringreturn _deco1def deco2(ex):def _deco2(string):print('deco2被调用前')string = ex(string)if 'ZMAN' in string:string = 'hello, ' + stringelse:string = 'Is your name ' + string + '?'print('deco2被调用后,%s' % string)return stringreturn _deco2@deco1 @deco2 def func(string):print('func函数被调用')return stringfunc('ZMAN') deco1(deco2(func('John')))>>> deco1被调用前 deco2被调用前 func函数被调用 deco2被调用后,hello, ZMAN deco1被调用后,You are my old friend.deco1被调用前 deco2被调用前 func函数被调用 deco2被调用后,Is your name John? deco1被调用后,You are my new friend.
在这个例子中,我们主要要关注装饰器调用的先后顺序,此时func('ZMAN')和deco1(deco2(func('ZMAN')))是等同的,这个调用顺序大家一看就明白了吧~
九、实际应用
最后来个实际应用~好吧,我实在是绞尽脑汁了,写代码的时候正好在吃苹果,那就来个跟水果有关的实例吧(别打我 - -!)
#综合运用:简单地检测函数传参是否合法def deco(ex):def _deco(*args, **kwargs):print('***%s函数被调用前***' % ex.__name__)if args:if not isinstance(args[0], str):print('★店名参数错误:%s' % args[0])if not(isinstance(args[1], int) and args[1]>0):print('★员工参数错误:%s' % args[1])else:print('★未传入店名和员工数信息!')if kwargs:for i in kwargs:if not ((isinstance(kwargs[i], int)or isinstance(kwargs[i], float))and kwargs[i]>0):print('★水果单价参数错误:%s:%r' % (i, kwargs[i]))else:print('★未传入水果单价信息!')a = ex(*args, **kwargs)print('***%s函数被调用后***\n' % ex.__name__)return _deco@deco # 假设传入几家水果店的名称、员工数以及水果单价。店名为字符,员工数为正整数,单价为正数 def func(*args, **kwargs):print('***函数func被调用***')brief = argsdetail = kwargsreturn(brief, detail)func('水果之家', -4, apple=3.5, strawberry=6, orange=3, cherry=8.5,) func(123, 8, apple=3, orange=2,) func('天然果园', 0.2, ) func()>>> ***func函数被调用前*** ★员工参数错误:-4 ***函数func被调用*** ***func函数被调用后******func函数被调用前*** ★店名参数错误:123 ***函数func被调用*** ***func函数被调用后******func函数被调用前*** ★员工参数错误:0.2 ★未传入水果单价信息! ***函数func被调用*** ***func函数被调用后******func函数被调用前*** ★未传入店名和员工数信息! ★未传入水果单价信息! ***函数func被调用*** ***func函数被调用后***
代码有点长,但是只要大家耐心看,其实还是挺简单的,没有什么花里胡哨的东西。这个装饰器用来检测传参是否合法~
十、小结
第一篇洋洋洒洒那么多个例子,终于写完了!利用“装饰器”,我们无须改写原函数,就能对它进行功能扩充,比如计时、检测传参、记录日志等等。就比如我们有一把枪,我们可以给它加上消音器,又或者是刺刀…不用的时候就拿掉,还是原来的枪~~
(本文难免有写错或不足的地方,希望大家不吝赐教哦~谢谢!)
转载于:https://www.cnblogs.com/noahzn/p/4294511.html
Noah的学习笔记之Python篇:装饰器相关推荐
- JavaScript学习笔记(四十四) 装饰器
装饰器模式(Decorator) 在装饰器模式中,可以在运行时给一个对象动态的添加额外的功能.当和静态类打交道的时候(static classes),这可能是一个挑战.但在JavaScript中,对象 ...
- 设计模式学习笔记(3)装饰器
本文实例代码:github.com/JamesZBL/ja- 装饰器(Decorator)模式用于动态地给一个对象添加一些额外的职责. 就增加功能来说, Decorator模式相比生成子类更为灵活.装 ...
- 编程学习笔记之python深入之装饰器案例及说明文档[图]
编程学习笔记之python深入之装饰器案例及说明文档[图] 装饰器即在不对一个函数体进行任何修改,以及不改变整体的原本意思的情况下,增加函数功能的新函数,因为这个新函数对旧函数进行了装饰,所以称为装饰 ...
- 学习笔记之——Python中类和对象的理解
学习笔记之--Python中类和对象的理解 面向对象的含义和特性 类 Python中类的定义.结构.创建 Python类的定义 Python类的结构 类的创建 类的属性 类的方法 对象 对象的创建 参 ...
- 《软技能-代码之外的生存指南》学习笔记之理财篇
<软技能–代码之外的生存指南>学习笔记之理财篇 作者:[美] John Z. Sonmez 摘要:这是⼀本真正从"⼈"(⽽⾮技术也⾮管理)的⾓度关注软件开发⼈员⾃⾝发展 ...
- flink1.12.0学习笔记第1篇-部署与入门
flink1.12.0学习笔记第 1 篇-部署与入门 flink1.12.0学习笔记第1篇-部署与入门 flink1.12.0学习笔记第2篇-流批一体API flink1.12.0学习笔记第3篇-高级 ...
- 《软技能--代码之外的生存指南》学习笔记之生产力篇
<软技能–代码之外的生存指南>学习笔记之生产力篇 作者:[美] John Z. Sonmez 摘要:这是⼀本真正从"⼈"(⽽⾮技术也⾮管理)的⾓度关注软件开发⼈员⾃⾝发 ...
- RCNN学习笔记——第三篇: 实现FRCNN网络训练、评价与预测(附全部源码)
RCNN学习笔记--第三篇: 实现FRCNN网络训练.评价与预测(附全部源码) 本文是个人根据B站大佬Bubbliiiing的FRCNN系列视频同步完成FRCNN训练,记录心得和遇见的问题. 关于RC ...
- 2021-09-01 学习笔记:Python爬虫、数据可视化
2021-09-01 学习笔记:Python爬虫.数据可视化 结于2021-09-07: 内容来自 成都工业大学 数字媒体专业实训: 主要内容: PyCharm开发Python脚本的基础配置: Pyt ...
最新文章
- TreeMap源码分析,看了都说好
- 比特币现金反弹,区块链是极好机遇
- 陈丹琦带着清华特奖学弟发布新成果:打破谷歌BERT提出的训练规律!这个庆祝方式太学神了吧...
- 十个非常有创意的验证码设计
- 曹大带我学 Go(12)—— 面向火焰图编程
- 动态规划训练10 [Coloring Brackets CodeForces - 149D]
- python实现离线翻译_10分钟教你用Python实现微信翻译机器人
- 静态路由配置_10 路由器间的静态路由及OSPF路由配置
- 企业或将借助OA走出经济危机
- IIS 7中ISAPI筛选器配置
- LeetCode:旋转链表【61】
- free、vmstat监视内存使用情况
- python顺序查找算法解释_顺序查找算法详解(包含C语言实现代码)
- 一次澄清:数据分析思维五大误区
- #HTTP协议学习# (六)代理
- Android获取地理坐标,Android 通过经纬度获取地理位置信息
- 使用 Git 管理 Vim 插件
- 计算机win7如何连接wifi网络,细说win7怎么共享wifi
- Docker进阶篇超详细版(https://www.bilibili.com/video/BV1kv411q7Qc)
- Shiro 之 Subject 类
热门文章
- [ORACLE]删除表的purge用法
- Maven入门,读这篇文章就够了
- 【iScroll源码学习01】准备阶段 - 叶小钗
- java电脑目录的遍历
- ViewBag在网页上的使用
- MGR中gtid_executed不连续的问题分析
- Fiddler手机抓包工具的使用教程
- Android Cannot execute task: the task has already been executed (a task can be executed only once)
- iOS 上利用 fallback 机制为不同语言的文字 (script) 设定字体,从而使得文本混排更为优雅...
- 【b站黑马程序员学习笔记-shell入门编程】