为什么说想到Python中的装饰器是天才
为什么说想到Python中的装饰器是天才
只需一个@符号就能分析、测试和重复使用你的代码
带着魔杖的仙女在Python代码中飞舞
软件中有没有什么是神奇的小魔法? 有,装饰器却非常接近!
如果说有一件事使Python难以置信地成功,那就是它的可读性。其他一切都取决于此:如果代码不可读,就很难维护。那么它也对初学者不友好--一个被不可读的代码弄得晕头转向的新手,有一天也不会尝试写自己的代码。
在装饰器出现之前,Python 已经是可读的,并且对初学者友好。但随着语言开始被用于越来越多的事情,Python 开发者感到需要越来越多的功能,同时又不至于杂乱无章,使代码无法阅读。
装饰器是一个完美实现功能的典型例子。它确实需要花点时间来理解,但这是值得的。当你开始使用它们时,你会注意到它们不会使事情过度复杂化,并使你的代码变得整洁而时髦。
在其他事情之前:高阶函数
简而言之,装饰器是处理高阶函数的一种整洁的方式。所以让我们先来看看这些
返回函数的函数 假设你有一个函数,greet() - 它向你传递的任何对象致意
假设你有另一个函数,simon() - 它在适当的地方插入 "Simon"
我们怎样才能把这两个函数结合起来呢? 在你看下面的内容之前先想一想。
def greet(name): return f"Hello, {name}!"
def simon(func): return func("Simon")
simon(greet)The output is 'Hello, Simon!'.
输出是 "你好,西蒙!"
希望这对你了解函数返回一个函数有意义!
当然,我们可以直接调用greet("Simon")。然而,重点是我们可能想把 "Simon "放到许多不同的函数中。如果我们不使用 "Simon",而是使用更复杂的东西,我们可以通过把它打包到simon()这样的函数中来节省大量的代码行。
函数中的函数
我们也可以在其他函数中定义函数。这一点很重要,因为装饰器也会这样做。如果没有装饰器,它看起来像这样。
下面的函数是接受参数 gpa 成绩,如果是‘yes’或大于‘90’分则调用函数 congrats() 否则,调用函数 encourage()
#练习修改
def respect(gpa): def congrats(): return "Congrats, Your gpa is excellent!"
def encourage(): return "You're have change to try again"
if gpa == "yes": return congrats() else: return encourage()
gpa = '91' #'python'gpa = "no"
print(f"{gpa},{respect(gpa)}")
#output:no,You're have change to try again
另外找时间讲一个意外:
print(gpa > '90')# 注意字符串的比较结果意外吧?
函数 respect() 返回一个函数; respect("yes") 返回祝贺函数, respect("brother") (或其他参数代替 "brother")返回鼓励函数。
要调用这些函数,请输入 respect("yes") 和 respect("brother"),就像普通函数一样。
明白了吗?那么你就可以为装饰者做好准备了!
代码是美丽的书呆子
在电脑屏幕前显示<code/is/beautiful>的女人
Python装饰器的ABC 带有@符号的函数 让我们尝试一下前面两个概念的组合:一个函数接收另一个函数,并定义一个函数。听起来很匪夷所思?考虑一下这个。
def startstop(func): def wrapper(): print("开始...") func() print("完成了!") 返回包装器def roll(): print("在地上打滚,笑死人了 XD")
roll()#OUPUT:
Starting...Rolling on the floor laughing XDFinished!
最后一行确保我们不再需要调用
startstop(roll)()
roll()就足够了。你知道这个调用的输出是什么吗?如果你不确定的话,就自己试试吧!
现在,作为一个非常好的替代方案,我们可以在定义startstop()之后直接插入这个。
@startstopdef roll(): print("在地板上笑着打滚 XD")
这样做是一样的,但是在开始时就把roll()和startstop()粘在一起了。
增加了灵活性
为什么会有这样的作用?这不是要消耗和以前一模一样多的代码行吗?
在这种情况下,是的。但是一旦你要处理稍微复杂的东西,它就会变得非常有用。这一次,你可以把所有的装饰器,即上面的def startstop()
部分移到它自己的模块里。
也就是说,你把它们写进一个叫做decorators.py
的文件,然后在你的主文件中写上类似这样的内容。
from decorators import startstop@startstopdef roll(): print("在地上打滚,笑死我了XD")
原则上,你可以不使用
decorators.py
来做这个。但这种方式使生活更简单,因为你不必再处理嵌套函数和无休止的括号计算了。
你也可以同时再嵌套其他装饰器。譬如计算函数执行时间的 exectime
from decorators import startstop, exectime@exectime@startstopdef roll(): print("在地上打滚,笑死人了 XD")
注意,我们还没有定义exectime()
,但你会在看到它。它是一个可以测量Python中一个过程所需时间的函数。这样的嵌套相当于这样的一行。
导入time
时间库
import time
# 用来计算持续时间的装饰器# 被任何函数占用的时间。
def exectime(func): # 在inner1内添加参数。 # 如果函数需要任何参数。 # 可以像这样添加。 def inner1(*args, **kwargs): # 储存函数执行前的时间 begin = time.time()
func(*args, **kwargs)
# 储存函数执行后的时间 end = time.time() print("Total time taken in : " , func.__name__, end - begin)
return inner1
现在就可以正常运行了
# 调用上面已经定义excetime函数!from decoratorsRoll import startstop, exectime @exectime@startstopdef roll(): time.sleep(3) print("Rolling on the floor laughing XD")roll()
roll = exectime(startstop(roll))print(roll())
Starting...Rolling on the floor laughing XDFinished!Total time taken in : wrapper 3.0007543563842773
括号内的计数开始了! 想象一下,你有五六个这样的函数相互嵌套在一起。装饰器的符号不是比这种嵌套的混乱更容易阅读吗?
你甚至可以在接受参数的函数上使用装饰器。现在想象一下,在上面那行中有几个参数,你的混乱就会完成。装饰器让它变得整齐划一。
最后,你甚至可以向你的装饰器添加参数--比如@mydecorator(argument)。是的,你可以不用装饰器来做这一切。但是,我祝愿你在三周后重读你的无装饰器的代码时,会有很多乐趣......
女人站在桌子上,上面放着电脑、浓缩咖啡杯和花瓶
装饰者使一切变得更容易
应用:装饰者切入的地方 现在,我希望能说服你,装饰器使你的生活轻松三倍,让我们看看一些经典的例子,在这些例子中,装饰器基本上是不可缺少的。
测量执行时间 上面的写法稍作变化:time.perf_counter()
假设我们有一个叫做waste time()的函数,我们想知道它需要多长时间执行完函数。那么,就用一个装饰器:
import timedef measuretime(func): def wrapper(): starttime = time.perf_counter() func() endtime = time.perf_counter() print(f"Time needed: {endtime - starttime} seconds") return wrapper
@measuretimedef wastetime(): sum([i**2 for i in range(1000000)])wastetime()
十几行代码,我们就完成了! 另外,你可以在任意多的函数上使用 measuretime()
。
减缓代码速度
有时你不想立即执行代码,而是要等待一段时间。这时,减速装饰器就派上用场了。
import timedef sleep(func): def wrapper(): time.sleep(300) return func() return wrapper@sleepdef wakeup(): print("Get up! Your break is over.")wakeup()
调用wakeup()
使得你可以休息5分钟,之后你的控制台会提醒你回去工作。
测试和调试
假设你有一大堆不同的函数,你在不同的阶段调用,而你对什么时候被调用失去了概览。通过对每个函数定义的简单装饰器,你可以使其更加清晰。就像这样。
def debug(func): def wrapper(): print(f"Calling {func.__name__}") return wrapper@debugdef scare(): print("Boo!")scare()
这里有一个更详细的例子。不过要注意的是,要理解这个例子,你必须检查如何用参数来装饰函数。不过,这还是值得一读的!
重用代码
这一点不言而喻。如果你已经定义了一个函数decorator(),你就可以在你的代码中到处撒上@decorator。说实话,我认为没有比这更简单的了。
处理登录
如果你有一些功能只有在用户登录后才能访问,使用装饰器也是相当容易的。我会让你参考完整的例子,但原理很简单:首先你定义一个类似login_required()
的函数。在任何需要登录的函数定义之前,你弹出@login_required
我想说,这让调用变得很简单!
语法糖--为什么Python是如此的甜蜜
Python有一个很大的诱惑力:它是如此容易理解,即使你不是一个受过训练的计算机科学家,而只是想让事情运转,帮你快速上手解决问题!
如果C++是一个橙子,那么Python就是一个菠萝:营养相似,但甜度要高三倍。装饰器只是其中的一个因素。
但我希望你已经明白了为什么它是如此大的一个甜味因素。合成糖为你的生活增添一些乐趣!这就是合成糖。没有健康风险,除了让你的眼睛粘在屏幕上。
我祝愿你有很多甜蜜的代码!
本文由 mdnice 多平台发布
为什么说想到Python中的装饰器是天才相关推荐
- python装饰器原理-python 中的装饰器及其原理
装饰器模式 此前的文章中我们介绍过装饰器模式: 装饰器模式中具体的 Decorator 实现类通过将对组建的请求转发给被装饰的对象,并在转发前后执行一些额外的动作来修改原有的部分行为,实现增强 Com ...
- python类装饰器详解-python 中的装饰器详解
装饰器 闭包 闭包简单的来说就是一个函数,在该函数内部再定义一个函数,并且这个内部函数用到了外部变量(即是外部函数的参数),最终这个函数返回内部函数的引用,这就是闭包. def decorator(p ...
- python中的装饰器decorator
python中的装饰器 装饰器是为了解决以下描述的问题而产生的方法 我们在已有的函数代码的基础上,想要动态的为这个函数增加功能而又不改变原函数的代码 例如有三个函数: def f1(x):return ...
- python编写装饰器_写python中的装饰器
python中的装饰器主要用于在已有函数实现功能前附加需要输出的信息,下面将用实例展示我如何写装饰器. 首先分别尝试写装饰器装饰一个无参函数和一个有参函数(被装饰函数仅输出,无返回值情况下) 1 de ...
- python中的装饰器(基础装饰器)
文章目录 一 前置知识-高阶函数,闭包 1. 高阶函数 2. 闭包 二 函数装饰器 1. 什么是装饰器(原理)? 2. 装饰器的实现 3. 何时执行装饰器 4. wraps方法 三 类装饰器 一 前置 ...
- [转载]理解PYTHON中的装饰器
[翻译]理解PYTHON中的装饰器 来源stackoverflow上的问题 链接 python的函数是对象 要理解装饰器,首先,你必须明白,在python中,函数是对象. 这很重要. 简单例子来理解为 ...
- python中的装饰器有哪些-python 装饰器以及开发中常用的例子
有时候我们想为多个函数,同意添加某一种功能,比如及时统计,记录日志,缓存运算结果等等,而又不想改变函数代码 那就定义装饰器函数,用它来生成一个在原函数基础添加了新功能的函数,代替原函数 参考金角大王的 ...
- python中的装饰器怎么运行_Python 装饰器入门(上)
翻译前想说的话: 这是一篇介绍python装饰器的文章,对比之前看到的类似介绍装饰器的文章,个人认为无人可出其右,文章由浅到深,由函数介绍到装饰器的高级应用,每个介绍必有例子说明.文章太长,看完原文后 ...
- Python中的装饰器是什么?装饰器是如何工作的?
Python很早就引入了装饰器--在PEP-318中,作为一种简化函数和方法定义方式的机制,这些函数和方法在初始定义之后必须进行修改. 这样做的最初动机之一是,使用classmethod和static ...
最新文章
- hash 值重复_程序员:判断对象是否重复,不重写equals和hashcode不行吗?
- 厦门大学计算机专业录取分数线2019,厦门大学2019年本科生录取分数线
- 深入浅出 MyBatis 的一级、二级缓存机制
- 世界坐标系到观察坐标系的变换步骤_《3D数学基础》提炼总结(九)矩阵和线性变换...
- php常用的十个代码片段,转载
- 计算机职称excel2007,职称计算机Excel2007中文电子表格考试大纲
- php xlsx里插入图片_常见的 PHP 面试题和答案分享
- 曝苹果iPhone 13将于8月开始大批量产,恶劣天气不会造成影响
- 能源路由器入门必读:面向能源互联网的架构和功能
- PeopleCert认证证书核验真伪(含ITIL、PRINCE2、DevOps、Scrum……等证书)
- html5 |移动 游戏 毕业设计,移动平台下基于HTML5的教育游戏研究与设计
- 面试官:请实现单行文本居中,多行文本左对齐?
- EasyExcel导出Excel设置单元格文本格式(亲测有效)
- 【点云处理技术之PCL】点云配准算法之NDT
- Python AutoCAD 修改
- #Eclipse IDE for Java EE Developers 的下载及初步使用
- 安装dplyr报错之rlang’ 0.4.5,但需要的是>= 0.4.10
- 微软谷歌苹果耳机大战 智能竞赛的又一战场
- 宁波银行金融科技面试
- 【TS TSP】基于matlab禁忌搜索求解旅行商问题【含Matlab源码 447期】
热门文章
- 处理表中id字段中,序号顺序不连贯
- 易保全亮相中国独角兽商机大会(长沙站),区块链应用助力企业家轻松布局
- 361页13万字“智慧公安”系统工程设计方案
- python实现qq登录腾讯视频_Python爬取腾讯视频评论的思路详解
- 格式化字符串php代码,格式化字符串
- python如何读取文件内容求和_python读文件统计次数和求和怎么写?
- Machine Learning --- zero-mean whiten(data preprocessing)
- springboot高考志愿选择系统 -计算机毕设 附源码68335
- Linux日志服务器_ELK搭建
- 自学Python可以吗?怎样从零基础到大师?我写这篇文章告诉你