您当前的位置:首页 > 电脑百科 > 程序开发 > 语言 > Python

大道至简,Python 装饰器 的通俗讲解

时间:2021-04-09 10:23:25  来源:  作者:软件测试开发技术栈

什么是Python/ target=_blank class=infotextkey>Python装饰器?

顾名思义,从字面意思可以理解为,它是用来"装饰"Python的工具,使得代码更具有Python简洁的风格。装饰器本质上是Python函数,能够实现让其他函数在不需要做任何代码变动的前提下增加额外功能。


为什么用装饰器?

装饰器是通过某种方式来增强函数的功能。当然,我们可以通过很多方式来增强函数的功能,只是装饰器有一个无可替代的优势——简洁且不改变函数内部代码。

只需要在被修饰函数上方填加一个@修饰函数,就可以对这个函数增加额外功能。


装饰器应用场景有哪些?

装饰器最大的优势是用于解决重复性的操作,其主要使用的场景有如下几个:

  • 日志输出
  • 类型检查
  • 鉴权(权限认证)
  • 重试等等

当然,如果遇到其他重复操作的场景也可以从装饰器的角度思考,如何提高代码的简洁性。通过可以抽离大量与函数功能本身无关的重复代码到装饰器中,概括的讲,装饰器的作用就是为已经存在的函数添加额外的功能。


简单示例

下面就以一个简单的例子来看一下它的作用。如果我们要对每个函数的增加重试机制,不使用装饰器,通常会是这样的,如下:

大道至简,Python 装饰器 的通俗讲解

 

在ops函数里通过for遍历以及try … except … else异常处理实现简单重试,执行上述代码,输出结果为:

大道至简,Python 装饰器 的通俗讲解

 

接下来,我们使用装饰器,实现重试机制,具体实现如下:

大道至简,Python 装饰器 的通俗讲解

 

通过编写一个重试机制的装饰器fun_retry,被修饰函数ops的作为装饰器的参数,然后返回函数retry

在fun_retry中嵌套了一个retry函数,那么retry是如何获取fun这个参数来执行的?,可是retry并没有接受fun这个传参,这就是Python里的闭包的概念,闭包就是指运行时自带上下文的函数,如这里的retry函数,它运行的时候自带了上层函数fun_retry传给他的fun这个函数,所以才可以在运行时对fun进行处理和输出。

然后再每个被修饰函数上面加上@fun_retry来调用装饰器,对不同的函数增加重试机制,即可省略每个函数里面的7行代码,实现在函数不需要做任何代码变动的前提下增加重试功能。

执行上述代码,输出结果为:

大道至简,Python 装饰器 的通俗讲解

 

通过执行结果,也可以发现,当Python解释器执行到@fun_retry时,就开始进行装饰了,相当于执行了如下代码:fun_retry(ops)。


带参数的装饰器

通过前面简单的实例介绍,应该已经大致清楚装饰器的作用和基本用法——通过闭包来实现装饰器,函数(ops)作为外层函数(fun_retry)的传入参数,然后在内层函数(retry)中运行、附加功能,随后把内层函数作为结果逐层返回。

除了上述简单的用法,装饰器还有更高的灵活性,例如带参数的装饰器。

带参数的修饰器并没有太复杂,其实就是在上述基本的装饰器的基础上在外面套一层接收参数的函数。

比如,我们认为现有的重试机制灵活性很差,需要它更加灵活的进行重试,例如支持修改重试次数、重试等待时间等,这时候可以把重试次数、重试等待时间作为装饰器的参数,如下:

大道至简,Python 装饰器 的通俗讲解

 

可以看出,在原有的基础上装饰器外层又嵌套了一层函数fun_retry_more用来接收参数,这样的话在ops函数前面调用时可以给装饰器传入参数,这样的输出结果是:

大道至简,Python 装饰器 的通俗讲解

 

可能有人会有一个疑问,如果我的被修饰函数 ops 需要参数怎么办?如果 ops 函数接收两个、三个参数,甚至更多呢?当装饰器不知道 ops 到底有多少个参数时,我们可以用*args 来代替,同样对于关键字参数,我们可以使用**kwargs来代替,args是一个数组,kwargs一个字典,我们在上面例子中也有所体现,def retry(args, **kwargs)。这样它就能够接受任意数量和类型的参数并把它们传递给被包装的方法,使得我们能够用这个装饰器来装饰任何方法。


对带有返回值的函数进行装饰

大道至简,Python 装饰器 的通俗讲解

 

我们仅需要对retry闭包进行如上修改,将fun()的返回值赋给re_v,并且retry闭包中增加return 返回re_v即可,执行上述代码,结果如下:

大道至简,Python 装饰器 的通俗讲解

 


保留元信息的装饰器

在修饰器中有一个细节很少有人提及,那就是保留被修饰对象的元信息的装饰器

什么是函数的元信息?

就是函数本书的一些基本信息,例如函数名、函数文档等,我们可以通过func.__name__获取函数名、可以通过func.__doc__获取函数的文档信息,用户也可以通过注解等方式为函数添加元信息。

使用装饰器极大地复用了代码,但是他有一个缺点就是原函数的元信息不见了,比如函数的docstring、name、参数列表,如下:

大道至简,Python 装饰器 的通俗讲解

 

使用装饰器极大地复用了代码,但是他有一个缺点,就是被修饰函数的元信息丢失了,执行上述代码,执行结果如下:

大道至简,Python 装饰器 的通俗讲解

 

可以通过使用Python自带模块functools中的wraps来保留被修饰函数的元信息。

大道至简,Python 装饰器 的通俗讲解

 

只需要在代码中加入@wraps(fun)即可保留函数的元信息。执行上述代码,输出结果为:

大道至简,Python 装饰器 的通俗讲解

 


装饰器顺序

一个函数还可以同时定义多个装饰器,比如:

大道至简,Python 装饰器 的通俗讲解

 

它的执行顺序是从里到外,最先调用最里层的装饰器,最后调用最外层的装饰器,它等效于:

大道至简,Python 装饰器 的通俗讲解


Tags:Python 装饰器   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,如有任何标注错误或版权侵犯请与我们联系(Email:2595517585@qq.com),我们将及时更正、删除,谢谢。
▌相关推荐
什么是Python装饰器?顾名思义,从字面意思可以理解为,它是用来"装饰"Python的工具,使得代码更具有Python简洁的风格。装饰器本质上是Python函数,能够实现让其他函数在不需要做任何...【详细内容】
2021-04-09  Tags: Python 装饰器  点击:(623)  评论:(0)  加入收藏
▌简易百科推荐
近几年 Web3 被炒得火热,但是大部分人可能还不清楚什么是 Web3,今天就让w3cschool编程狮小师妹带你了解下 Web3 是什么?与我们熟知的 Web1 和 Web2 又有什么区别呢?web3.0什么是...【详细内容】
2022-07-15  编程狮W3Cschool    Tags:Web3.0   点击:(2)  评论:(0)  加入收藏
1、让我们一起来看下吧,直接上图。 第一眼看到是不是觉得很高逼格,暗黑画风,这很大佬。其实它就是------AidLearning。一个运行在安卓平台的linux系统,而且还包含了许多非常强大...【详细内容】
2022-07-15  IT智能化专栏    Tags:AidLearning   点击:(2)  评论:(0)  加入收藏
真正的大师,永远都怀着一颗学徒的心! 一、项目简介 今天说的这个软件是一款基于Python+vue的自动化运维、完全开源的云管理平台。二、实现功能 基于RBAC权限系统 录像回放 ...【详细内容】
2022-07-14  菜鸟程序猿    Tags:Python   点击:(3)  评论:(0)  加入收藏
前言今天笔者想和大家来聊聊python接口自动化的MySQL数据连接,废话不多说咱们直接进入主题吧。 一、什么是 PyMySQL?PyMySQL是在Python3.x版本中用于连接MySQL服务器的一个库,P...【详细内容】
2022-07-11  测试架构师百里    Tags:python   点击:(19)  评论:(0)  加入收藏
aiohttp什么是 aiohttp?一个异步的 HTTP 客户端\服务端框架,基于 asyncio 的异步模块。可用于实现异步爬虫,更快于 requests 的同步爬虫。安装pip install aiohttpaiohttp 和 r...【详细内容】
2022-07-11  VT漫步    Tags:aiohttp   点击:(15)  评论:(0)  加入收藏
今天我们学习下 Queue 的进阶用法。生产者消费者模型在并发编程中,比如爬虫,有的线程负责爬取数据,有的线程负责对爬取到的数据做处理(清洗、分类和入库)。假如他们是直接交互的,...【详细内容】
2022-07-06  VT漫步    Tags:Python Queue   点击:(34)  评论:(0)  加入收藏
继承:是面向对象编程最重要的特性之一,例如,我们每个人都从祖辈和父母那里继承了一些体貌特征,但每个人却又不同于父母,有自己独有的一些特性。在面向对象中被继承的类是父类或基...【详细内容】
2022-07-06  至尊小狸子    Tags:python   点击:(25)  评论:(0)  加入收藏
点击上方头像关注我,每周上午 09:00准时推送,每月不定期赠送技术书籍。本文1553字,阅读约需4分钟 Hi,大家好,我是CoCo。在上一篇Python自动化测试系列文章:Python自动化测试之P...【详细内容】
2022-07-05  CoCo的软件测试小栈    Tags:Python   点击:(27)  评论:(0)  加入收藏
第一种方式:res = requests.get(url, params=data, headers = headers)第二种方式:res = requests.get(url, data=data, headers = headers)注意:1.url格式入参只支持第一种方...【详细内容】
2022-07-05  独钓寒江雪之IT    Tags:Python request   点击:(19)  评论:(0)  加入收藏
什么是python类的多态python的多态,可以为不同的类实例,或者说不同的数据处理方式,提供统一的接口。用比喻的方式理解python类的多态比如,同一个苹果(统一的接口)在孩子的眼里(类实...【详细内容】
2022-07-04  写小说的程序员    Tags:python类   点击:(28)  评论:(0)  加入收藏
站内最新
站内热门
站内头条