6.0 Python 使用函数装饰器

装饰器可以使函数执行前和执行后分别执行其他的附加功能,这种在代码运行期间动态增加功能的方式,称之为"装饰器"(Decorator),装饰器的功能非常强大,装饰器一般接受一个函数对象作为参数,以对其进行增强,相当于C++中的构造函数,与析构函数。

装饰器本质上是一个python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象.它经常用于有迫切需求的场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等场景.装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离出大量与函数功能本身无关的雷同代码并继续重用.

  • 装饰器本身也是一个函数,其作用是,用于装饰其他函数.
  • 装饰器是一个闭包函数是嵌套函数,通过外层函数提供嵌套函数的环境
  • 装饰器在权限控制,增加额外功能,如增加记录日志,缓存处理,发送邮件用的比较多

6.1 无参装饰器

原函数中不带参数的装饰器,如下例子假设:我定义了一个函数lyshark(),现在想要在不改变原来函数定义的情况下,在函数运行前打印一段话,函数运行后打印另一段话,此时我们可以使用装饰器的装饰功能来简单的实现这个需求.

>>> import os
>>> import sys
>>> 
>>> def outer(function):def inner():print("主函数开始执行前,会先执行我!")result=function()print("主函数执行结束后,要在执行我!")return resultreturn inner# (1) @ + 函数名,直接作用在需要装饰的函数上一行
# (2) 自动执行outer函数并且将下面的函数名lyshark()当做参数传递到outer()
# (3) 将outer函数的返回值inner,重新赋值给lyshark()函数
>>> @outer
def lyshark():print("lyshark 的主函数体,装饰器在装饰我(*^_^*)")return "check ok"#==调用并执行函数,结果如下==========================================
>>> ret=lyshark()
主函数开始执行前,会先执行我!
lyshark 的主函数体,装饰器在装饰我(*^_^*)
主函数执行结束后,要在执行我!>>> print("lyshark()函数的返回值: ",ret)
lyshark()函数的返回值:  check

上方代码的执行流程是这样的,步骤如下:

  • 1.当我们调用lyshark()函数时,会自动检查lyshark()函数上是否有装饰器
  • 2.如果有则将lyshark()函数的指针,传递给装饰器outer(function)
  • 3.outer(function)接到指针后,执行嵌套函数内的inner(),则先执行print打印一段话
  • 4.由于lyshark()函数指针,传递给了function变量,执行function()则相当于执行lyshark()
  • 5.接着最后一步执行打印一段结束的话,并执行返回,返回inner

6.2 有参装饰器

原函数带一个参数的装饰器: 我们在以上的案例中,给装饰器添加一个参数,并在内部使用这个参数.

>>> import os
>>> import sys
>>> 
>>> def outer(function):def inner(args):print("主函数开始执行前,会先执行我!")ret=function(args)print("主函数执行结束后,要在执行我!")return retreturn inner>>> @outer
def lyshark(args):print(args)return 0#==调用并执行函数,结果如下==========================================
>>> ret=lyshark("hello world!")
主函数开始执行前,会先执行我!
hello world!
主函数执行结束后,要在执行我!>>> print("lyshark 的返回值是:",ret)
lyshark() 函数的返回值是: 0

原函数带两个参数的装饰器: 接下来继续演示一下,带有两个参数的装饰器,3个4个,以此类推.

>>> import os
>>> import sys
>>> 
>>> 
>>> def outer(function):def inner(x,y):print("主函数开始执行前,会先执行我!")ret=function(x,y)print("主函数执行结束后,要在执行我!")return retreturn inner>>> @outer
def lyshark(x,y):print(x,y)return 0#==调用并执行函数,结果如下==========================================
>>> ret=lyshark("Hello","LyShark")
主函数开始执行前,会先执行我!
Hello LyShark
主函数执行结束后,要在执行我!>>> print("lyshark() 函数的返回值是:",ret)
lyshark() 函数的返回值是: 0

传递一个万能参数: 装饰器也可传递一个万能参数,通过此参数传递列表字典等.

>>> import os
>>> import sys
>>> 
>>> def outer(function):def inner(*args,**kwargs):print("主函数开始执行前,会先执行我!")ret=function(*args,**kwargs)print("主函数执行结束后,要在执行我!")return retreturn inner>>> @outer
def lyshark(*args):print(args)return 0#==调用并执行函数,结果如下==========================================
>>> num=[1,2,3,4,5]
>>> ret=lyshark(num)
主函数开始执行前,会先执行我!
([1, 2, 3, 4, 5],)
主函数执行结束后,要在执行我!
>>> 
>>> print("lyshark() 函数的返回值是:",ret)
lyshark() 函数的返回值是: 0#==调用并执行函数,结果如下==========================================
@outer
def lyshark_kw(*args,**kwargs):print(args,kwargs)return 0num=[1,2,3,4,5]
kw={"1001":"admin","1002":"guest"}
ret=lyshark_kw(num,kw)

一次使用两个装饰器装饰函数: 如果一个装饰器不够用的话,我们可以使用两个装饰器,首先将函数与内层装饰器结合然后在与外层装饰器相结合,要理解使用@语法的时候到底执行了什么,是理解装饰器的关键.

>>> import os
>>> import sys
>>> 
>>> def outer2(function2):def inner2(*args,**kwargs):print("装饰器2--->【开始】")ret=function2(*args,**kwargs)print("装饰器2--->【结束】")return retreturn inner2>>> def outer1(function1):def inner1(*args,**kwargs):print("装饰器1--->【开始】")ret=function1(*args,**kwargs)print("装饰器1--->【结束】")return retreturn inner1@outer2
@outer1
def lyshark():print("lyshark 函数被执行了")#==调用并执行函数,结果如下==========================================
>>> lyshark()
装饰器2--->【开始】
装饰器1--->【开始】
lyshark 函数执行了
装饰器1--->【结束】
装饰器2--->【结束】#==调用并执行函数,结果如下==========================================
@outer1
@outer2
def lyshark_and():print("lyshark_and 函数被执行了")>>> lyshark_and()
装饰器1--->【开始】
装饰器2--->【开始】
lyshark_and 函数执行了
装饰器2--->【结束】
装饰器1--->【结束】

6.3 带参装饰器

前面的装饰器本身没有带参数,如果要写一个带参数的装饰器怎么办,那么我们就需要写一个三层的装饰器,而且前面写的装饰器都不太规范,下面来写一个比较规范带参数的装饰器,下面来看一下代码,大家可以将下面的代码自我运行一下.

给装饰器本身添加参数: 接下来我们将给装饰器本身添加一些参数,使其能够实现参数传递.

>>> import functools
>>> import sys
>>> 
>>> def lyshark(temp=""):                                   #指定装饰器默认参数def decorator(function):                                #定义装饰器@functools.wraps(function)                          #使被装饰的装饰器的函数名不改变def wrapper(*args,**kwargs):print("主函数开始执行前,会先执行我!")print("{}:{}".format(temp,function.__name__))   #这里调用了装饰器temp变量ret=function(*args,**kwargs)print("主函数执行结束后,要在执行我!")return retreturn wrapperreturn decorator#==调用并执行函数,结果如下==========================================
>>> #如果不给装饰器加参数,那么这个装饰器将使用默认参数 temp="",来填充
>>> @lyshark()
def test(x):print(x+100)>>> test(100)
主函数开始执行前,会先执行我!
:test                         #这里由于没有传递参数则第一项为空,第二项是函数名称`function.__name__`取出的
主函数执行结束后,要在执行我!#==调用并执行函数,结果如下==========================================
>>> #下面是给装饰器一个参数,将不是用默认参数 temp="",将变成 temp="LyShark"
>>> @lyshark("LyShark")
def test(x):print(x+100)>>> test(100)
主函数开始执行前,会先执行我!
LyShark:test
主函数执行结束后,要在执行我!

给装饰器本身添加参数: 接下来我们将给装饰器本身添加两个参数,使其能够传递多个参数.

>>> import sys
>>> import os
>>> 
>>> def lyshark(x="Hello",y="LyShark"):def decorator(function):def wrapper():print("主函数执行前,应先执行我!")print(x,y)ret=function()print("主函数执行后,要执行我!")return retreturn wrapperreturn decorator#==调用并执行函数,结果如下==========================================
>>> #使用默认参数的装饰器:此时 x="Hello" y="LyShark"
>>> @lyshark()
def test():print("我是test(),主函数,装饰器在装饰我")>>> test()
主函数执行前,应先执行我!
Hello LyShark
我是test(),主函数,装饰器在装饰我
主函数执行后,要执行我!#==调用并执行函数,结果如下==========================================
>>> #给装饰器指定参数:此时 x="My Name Is :" y="LyShark"
>>> @lyshark("My Name Is :","LyShark")
def test():print("我是test(),主函数,装饰器在装饰我")>>> test()
主函数执行前,应先执行我!
My Name Is : LyShark
我是test(),主函数,装饰器在装饰我
主函数执行后,要执行我!

本文作者: 王瑞
本文链接: https://www.lyshark.com/post/63fd2e5b.html
版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/36731.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

安达发APS|生产计划排产软件助力加工制造业智能化转型

随着全球经济一体化的不断深入,市场竞争日益激烈,加工制造企业面临着巨大的生存压力。在这种情况下,企业对于生产计划的精细化管理需求日益迫切。为了适应这一市场需求,安达发推出了专门针对加工企业的APS生产计划排产软件&#x…

新一代构建工具 maven-mvnd

新一代构建工具 maven-mvnd mvnd的前世今生下载安装 mvndIDEA集成 mvnd的前世今生 maven 作为一代经典的构建工具,流行了很多年,知道现在依然是大部分Java项目的构建工具的首选;但随着项目复杂度提高,代码量及依赖库的增多使得ma…

简单易懂的 Postman Runner 参数自增教程

目录 什么是 Postman Runner? Postman Runner 如何实现参数自增? 步骤一:设置全局参数 步骤二:将全局参数带入请求参数 步骤三:实现参数自增 资料获取方法 什么是 Postman Runner? Postman Runner 是…

Python爬虫(1)一次性搞定Selenium(新版)8种find_element元素定位方式

selenium中有8种不错的元素定位方式,每个方式和应用场景都不一样,需要根据自己的使用情况来进行修改 8种find_element元素定位方式 1.id定位2.CSS定位3.XPATH定位4.name定位5.class_name定位6.Link_Text定位7.PARTIAL_LINK_TEXT定位8.TAG_NAME定位总结 …

【第一阶段】kotlin中反引号中的函数名特点

在kotlin中可以直接中文定义函数,使用反引号进行调用 eg: fun main() {2023年8月9日定义的函数(5) }private fun 2023年8月9日定义的函数(num:Int){println("反引号的用法$num") }执行结果 在Java中is,in可以定义方法,但是在kotlin中is,in是…

资料分析(三)—— 基期、现期、人口、增长量

基期 基期值 现期值 - 增长量 增长量/增长率 现期值/1&#xff08;间隔)增长率 化除为乘 &#xff1a;当增长率&#xff5c;r| < 5% 时&#xff0c;&#xff0c; 注&#xff1a;当选项首位相同&#xff0c;第二位也相同时&#xff0c;只能用直除 基期和差 (结合选…

SolidUI社区-根据Prompt打造人设

背景 随着文本生成图像的语言模型兴起&#xff0c;SolidUI想帮人们快速构建可视化工具&#xff0c;可视化内容包括2D,3D,3D场景&#xff0c;从而快速构三维数据演示场景。SolidUI 是一个创新的项目&#xff0c;旨在将自然语言处理&#xff08;NLP&#xff09;与计算机图形学相…

【openwrt学习笔记】dnsmasq源码阅读

目录 一、DHCP(Dynamic Host Configuration Protocol)1.1 前置知识1.2 参考链接1.3 IP地址分配代码分析rfc2131.cdhcp-common.cdhcp.c 1.4 几个小问题1.4.1 连续IP模式&#xff08;sequential_ip&#xff09;1.4.2 重新连接使用IP地址1.4.3 续约租期1.4.4 不同的MAC地址分配到相…

VS+Qt+C++旅游景区地图导航源码实例

程序示例精选 VSQtC旅游景区地图导航 如需安装运行环境或远程调试&#xff0c;见文章底部个人QQ名片&#xff0c;由专业技术人员远程协助&#xff01; 前言 这篇博客针对<<VSQtC旅游景区地图导航>>编写代码&#xff0c;代码整洁&#xff0c;规则&#xff0c;易读。…

【Vue框架】菜单栏权限的使用与显示

前言 在 【Vue框架】Vue路由配置 中的getters.js里&#xff0c;可以看到有一个应用程序的状态&#xff08;变量&#xff09;叫 permission_routes&#xff0c;这个就是管理前端菜单栏的状态。具体代码的介绍&#xff0c;都以注释的形式来说明。 1、modules\permission.js 1…

SpringBoot 将项目打包成 jar 包

SpringBoot 将项目打包成 jar 包 一、项目打包成 jar 包 首先在 pom.xml 文件中导入 Springboot 的 maven 依赖 <!-- 将应用打包成一个可以执行的 jar 包 --> <build><plugins><plugin><groupId>org.springframework.boot</groupId><…

学习笔记整理-面向对象-02-认识函数的上下文

一、认识函数的上下文 什么是上下文 垃圾分类&#xff0c;这是非常好的习惯&#xff0c;值得表扬随手关灯&#xff0c;这是非常好的习惯&#xff0c;值得表扬遛狗栓绳&#xff0c;这是非常好的习惯&#xff0c;值得表扬课后复习&#xff0c;这是非常好的习惯&#xff0c;值得…

【数据结构】单链表OJ题(二)

&#x1f525;博客主页&#xff1a;小王又困了 &#x1f4da;系列专栏&#xff1a;数据结构 &#x1f31f;人之为学&#xff0c;不日近则日退 ❤️感谢大家点赞&#x1f44d;收藏⭐评论✍️ 目录 一、链表分割 &#x1f4a1;方法一&#xff1a; 二、链表的回文 &#x…

hosts文件中被添加 windows10.microdone.cn

在网上搜了一圈逗说是之前下过征信中心的安全控件,是微通新成网络科技有限公司这家公司提供的,也是http://microdone.cn的运营商。后边只要使用代理,就会跳出来,所以常规处理操作就是去把浏览器上的安全控件卸载了。 参考 解决 windows10 的 代理频繁被自动篡改为windows10.mi…

利用python实现激光雷达LAS数据滤波的7种方式,使用laspy读写

激光雷达&#xff08;LiDAR&#xff09;数据在实际应用中可能受到噪声和不完美的测量影响&#xff0c;因此数据去噪和滤波方法变得至关重要&#xff0c;以提高数据质量和准确性。以下是一些常用的激光雷达数据去噪与滤波方法。 原始数据如下&#xff1a; 1. 移动平均滤波&…

kubernetes中PV和PVC

目录 一、PV、PVC简介 二、PV、PVC关系 三、创建静态PV 1.配置nfs存储 2.定义PV 3.定义PVC 4.测试访问 四、 搭建 StorageClass nfs-client-provisioner &#xff0c;实现 NFS 的动态 PV 创建 1. 配置nfs服务 2.创建 Service Account 3.使用 Deployment 来创建 NFS P…

Figma中文社区来啦,云端协作设计你准备好了吗?

Figma是改变产品设计协作方式的重要工具,但由于没有中文社区,对国内设计师的约束较大。而拥有全中文UI 界面、功能齐全的即时设计资源广场,恰好弥补了Figma的这一短板,它也将取代Figma成为设计师新宠。 1、UI组件集 Figma中文社区替代即时设计资源广场,拥有海量丰富的UI设计组…

【BEV Review】论文 Delving into the Devils of Bird’s-eye-view 2022-9 笔记

背景 一般来说&#xff0c;自动驾驶车辆的视觉传感器&#xff08;比如摄像头&#xff09;安装在车身上方或者车内后视镜上。无论哪个位置&#xff0c;摄像头所得到的都是真实世界在透视视图&#xff08;Perspective View&#xff09;下的投影&#xff08;世界坐标系到图像坐标系…

ssm柚子云电子商城java图书购物电子商务管理jsp源代码

本项目为前几天收费帮学妹做的一个项目&#xff0c;Java EE JSP项目&#xff0c;在工作环境中基本使用不到&#xff0c;但是很多学校把这个当作编程入门的项目来做&#xff0c;故分享出本项目供初学者参考。 一、项目描述 ssm柚子云电子商城 系统有2权限&#xff1a;前台、后…

SpringBoot笔记:SpringBoot 集成 Dataway 多数据源配置(二)

文章目录 前言核心代码和配置yml 配置注入多数据源常用Spi实现swagger 配置自定义 Udf指定数据源进行查询 前言 之前简单介绍了一下 Dataway 使用&#xff0c;本文继续介绍一下它的多数据源配置和使用。 核心代码和配置 yml 配置 # springboot多环境配置 #端口&#xff0c;…