详细分析Python装饰器(附Demo)

news2024/11/16 20:29:59

目录

  • 前言
  • 1. 基本知识
  • 2. 无参装饰器
  • 3. 有参装饰器
  • 4. 多个装饰器

前言

装饰器类似Java的切点切面增强

推荐阅读:

  1. 详细分析Spring中的@Around注解(附Demo)
  2. java框架 零基础从入门到精通的学习路线 附开源项目面经等(超全)
  3. Spring框架从入门到学精(全)

Python实战代码如下:

在这里插入图片描述

1. 基本知识

装饰器是Python语言中的一种高级功能,它允许将一个函数或者类“装饰”(即修改或增强)其他函数或者类的行为。装饰器本质上是一个可调用的对象,它接受一个函数或者类作为输入,并返回一个新的函数或者类

作用优点缺点
代码重用: 装饰器可以用来包装重复使用的功能或逻辑,提高代码的重用性

代码简洁: 装饰器可以将一些与主要逻辑无关的代码分离出来,使主要代码更加简洁易读

横切关注点(Cross-cutting Concerns): 装饰器可以用来处理与业务逻辑无关但又必须存在于多处的功能,例如日志记录、性能检测、权限验证等

动态增加功能: 装饰器可以在不修改被装饰对象的情况下,动态地增加新的功能或行为
提高代码的复用性和可维护性

使代码更加简洁,易于理解

允许动态地添加或修改对象的行为,而无需修改其原始定义
可能会增加代码的复杂性,特别是在使用多个装饰器的情况下

装饰器可能会改变被装饰对象的原始行为,导致难以调试

2. 无参装饰器

通过Demo了解如何增强

# 定义一个简单的装饰器函数 simple_decorator,接受一个函数作为参数
def simple_decorator(func):
    # 定义一个内部函数 wrapper,用于包装被装饰的函数
    def wrapper():
        print("Before calling the function")  # 在调用被装饰函数之前打印信息
        func()  # 调用被装饰的函数
        print("After calling the function")  # 在调用被装饰函数之后打印信息
    return wrapper  # 返回内部函数 wrapper

# 使用装饰器 simple_decorator 对 say_hello 函数进行装饰
@simple_decorator
def say_hello():
    print("执行一次say_hello")  # 打印信息,表示 say_hello 函数被执行了一次

# 调用被装饰后的 say_hello 函数,实际上会在函数执行前后打印额外的信息
say_hello()

截图如下:

在这里插入图片描述

3. 有参装饰器

额外添加了一个内部函数 decorator,它负责接收被装饰函数,并返回一个装饰器函数 wrapper。这种设计更符合装饰器的惯用方式,即装饰器函数接受参数(在这里是 n),然后返回一个装饰器函数,该装饰器函数再接受被装饰的函数,并返回一个新的函数(或者对原函数进行修改)

# 定义一个装饰器函数 repeat,接受一个参数 n,表示要重复执行的次数
def repeat(n):
    # 定义一个内部函数 decorator,该函数接受被装饰的函数作为参数 func
    def decorator(func):
        # 定义一个内部函数 wrapper,用于包装被装饰的函数,以实现重复执行的功能
        def wrapper(*args, **kwargs):
            # 使用 for 循环执行被装饰的函数 n 次
            for _ in range(n):
                func(*args, **kwargs)  # 调用被装饰的函数
        return wrapper  # 返回 wrapper 函数
    return decorator  # 返回 decorator 函数

# 使用装饰器 repeat(3) 对 greet 函数进行装饰,表示要重复执行 3 次
@repeat(3)
def greet(name):
    print(f"Hello, {name}!")  # 打印输出问候语

# 调用被装饰后的 greet 函数,实际上会重复打印三次问候语
greet("码农研究僧")

截图如下:

在这里插入图片描述

以下为错误显示:

def repeat(n):
    def wrapper(*args, **kwargs):
        func(*args, **kwargs)
    return wrapper
        


@repeat(3)
def greet(name):
    print(f"Hello, {name}!")

greet("码农研究僧")

装饰器 repeat 的内部函数 wrapper 中使用了 func(*args, **kwargs) 来调用被装饰的函数,但是在 repeat 函数内部并没有定义 func,因此会引发错误。正确的方式是在 repeat 内部定义一个参数来接收被装饰函数,并在 wrapper 中使用该参数来调用被装饰函数

4. 多个装饰器

以下代码整体逻辑如下:

  1. greet("manong") 被 bold 装饰器装饰,变成 bold(uppercase(greet))("manong")
  2. 首先 uppercase(greet) 被调用,得到大写的字符串 "HELLO, MANONG!"
  3. bold 装饰器再次被调用,将大写的字符串用 <b> 和 </b> 标签包裹起来,得到 <b>HELLO, MANONG!</b>
  4. 最终的结果被打印输出
# 定义装饰器 uppercase,将被装饰函数的返回值转换为大写
def uppercase(func):
    def wrapper(*args, **kwargs):
   		print(2)
        # 调用被装饰函数,并将结果转换为大写
        result = func(*args, **kwargs)
        print(3)
        return result.upper()
    return wrapper

# 定义装饰器 bold,将被装饰函数的返回值用 <b> 和 </b> 标签包裹起来
def bold(func):
    def wrapper(*args, **kwargs):
    	print(1)
        # 调用被装饰函数,并用 <b> 和 </b> 标签包裹返回结果
        result = func(*args, **kwargs)
        print(4)
        return f"<b>{result}</b>"
    return wrapper

# 先应用 bold 装饰器,再应用 uppercase 装饰器
@bold
@uppercase
def greet(name):
    return f"Hello, {name}!"

# 调用 greet 函数,并输出结果
print(greet("manong"))

截图如下:

在这里插入图片描述

当函数 greet 被装饰时, uppercase 装饰器会先执行,然后是 bold 装饰器。这意味着 uppercase 装饰器的 wrapper 函数会先被调用,然后是 bold 装饰器的 wrapper 函数

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

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

相关文章

如何实现Git Push之后自动部署到服务器?

在平时个人开发的过程中是不是有这样的烦恼&#xff1a; 项目开发完成&#xff0c;Push之后 登录服务器&#xff0c;手动git pull&#xff0c;然后运行部署命令 这真的很烦诶&#xff01; 那么能不能Git push之后&#xff0c;远端服务器自动 Git pull 然后运行部署命令呢&a…

内网安全之-NTLM协议详解

NTLM&#xff08;New Technology LAN Manager&#xff09;身份验证协议是微软用于Windows身份验证的主要协议之一。早起SMB协议以明文口令的形式在网络上传输&#xff0c;因此产生了安全性问题。后来出现了LM&#xff08;LAN Manager&#xff09;身份验证协议&#xff0c;它非常…

排序问题—java实现

冒泡排序 算法思想&#xff1a; 每次比较相邻元素&#xff0c;若逆序则交换位置&#xff0c;每一趟比较n-1次&#xff0c;确定一个最大值。故需比较n趟&#xff0c;来确定n个数的位置。 外循环来表示比较的趟数&#xff0c;每一趟确定一个最大数的位置内循环来表示相邻数字两…

2024考研国家线公布,各科分数线有哪些变化?考研国家线哪些涨了,哪些跌了?可视化分析告诉你

结论在文章结尾 2024考研国家线 一、近五年国家线趋势图-学术硕士 文学 管理学 工学照顾专业 体育学 交叉学科 军事学 历史学 理学 享受少数名族照顾政策的考生 中医类照顾专业 教育类 艺术类 医学 工学 哲学 法学 农学 经济学 二、近五年国家线趋势图-专业硕士 中医 应用心理 …

IPSEC VPN-详解原理

目录 IPSEC提供的安全服务 IPSEC协议簇 ​编辑 安全协议 1.传输模式 2. 隧道模式 AH ---鉴别头协议 AH提供的安全服务&#xff1a; AH头部 AH的保护范围 1.传输模式 2.隧道模式 ​编辑 ESP ---封装安全载荷协议 ESP提供的安全服务&#xff1a; ESP的头部 ESP的保护范围 1.传输…

如何选择合适的数据可视化工具?

如果是入门级的数据可视化工具&#xff0c;使用Excel插件就足够了&#xff01; Excel插件&#xff0c;tusimpleBI 是一款 Excel 图表插件&#xff0c;提供超过120项图表功能&#xff0c;帮助用户制作各种 Excel 所没有的高级图表&#xff0c;轻轻松松一键出图。 它能够制作10…

【送书福利!第一期】《ARM汇编与逆向工程》

&#x1f42e;博主syst1m 带你 acquire knowledge&#xff01; ✨博客首页——syst1m的博客&#x1f498; &#x1f618;《CTF专栏》超级详细的解析&#xff0c;宝宝级教学让你从蹒跚学步到健步如飞&#x1f648; &#x1f60e;《大数据专栏》大数据从0到秃头&#x1f47d;&…

SD-WAN解决企业在工业互联网时代的新困境

工业互联网迎来全新的发展契机&#xff0c;而SD-WAN技术将成为制造企业快速崭露头角的得力助手&#xff01; 制造业的数字化转型已成为经济全球化和数字化浪潮的必然产物。许多制造企业迅速向人口密集区域扩张&#xff0c;呈现出分支众多、布局分散的特点。随着工业互联网的蓬勃…

Linux环境开发工具之yum

前言 前面我们已经对基本的指令和权限进行了介绍&#xff0c;本期开始我们将介绍常用的开发工具。例如&#xff1a;软件包管理器yum。 本期内容介绍 Linux上安装软件的方式 什么是yum yum的相关操作 yum的本地配置和yum源 一、Linux上安装软件的方式 在介绍Linux上如何安装一…

upload-lab 11-20解法

pass11 查看代码 这里我们先解读下代码 $is_upload false; $msg null; if(isset($_POST[submit])){# 定义了白名单数组$ext_arr array(jpg,png,gif);# 截取上传文件名最后一个带点的文件后缀 $file_ext substr($_FILES[upload_file][name],strrpos($_FILES[upload_file][n…

10:00面试,10:06就出来了,问的问题有点变态。。。

从小厂出来&#xff0c;没想到在另一家公司又寄了。 到这家公司开始上班&#xff0c;加班是每天必不可少的&#xff0c;看在钱给的比较多的份上&#xff0c;就不太计较了。没想到8月一纸通知&#xff0c;所有人不准加班&#xff0c;加班费不仅没有了&#xff0c;薪资还要降40%…

SHELL——条件判断语句练习

目录 一、练习题目 二、解答过程 1、判断当前磁盘剩余空间是否有20G&#xff0c;如果小于20G&#xff0c;则将报警邮件发送给管理员&#xff0c;每天检查次磁盘剩余空间。 安装邮件服务 配置邮件服务 编写脚本work1.sh 添加计划任务 2、判断web服务是否运行&#xff1a;…

基于PyTorch的视频分类实战

1、数据集下载 官方链接&#xff1a;https://serre-lab.clps.brown.edu/resource/hmdb-a-large-human-motion-database/#Downloads 百度网盘连接&#xff1a; https://pan.baidu.com/s/1sSn--u_oLvTDjH-BgOAv_Q?pwdxsri 提取码: xsri 官方链接有详细的数据集介绍&#xf…

疯狂 META:Aavegotchi 新一季稀有度挖矿来了!

经过数周的激烈讨论和参与&#xff0c;AavegotchiDAO 再次投票决定资助新一季的稀有度挖矿活动&#xff0c;这也是我们神奇的第八季&#xff01;朋友们&#xff0c;我们又开始啦——拿出你们最好的装备&#xff0c;擦亮那些可穿戴设备&#xff0c;准备好赚钱吧&#xff01; 与…

HarmonyOS系统开发ArkTS入门案例及组件

目录 一、声明式UI 二、ArkTs 快速入门案例 三、组件 四、渲染控制 一、声明式UI 声明式UI就是一种编写用户界面的范式或方式、 ArArkTS 在继承了Typescript语法的基础上&#xff0c;主要扩展了声明式UI开发相关的能力。 声明式UI开发范式大致流程&#xff1a;定义页面…

IPv4到IPv6的过渡策略

IPv4到IPv6的过渡是一个复杂且必要的过程&#xff0c;随着全球互联网的不断发展&#xff0c;IPv4地址资源的枯竭使得向IPv6过渡成为一项紧迫的任务。IPv6提供了更广阔的地址空间、更高的安全性和更灵活的路由方式&#xff0c;是未来互联网发展的必然趋势。下面将详细阐述如何从…

面向对象【内部类】

什么是内部类 将一个类 A 定义在另一个类 B 里面&#xff0c;里面的那个类 A 就称为内部类&#xff08;InnerClass&#xff09;&#xff0c;类 B 则称为外部类&#xff08;OuterClass&#xff09; 为什么要声明内部类 具体来说&#xff0c;当一个事物 A 的内部&#xff0c;还…

基于SpringBoot的后勤管理系统【附源码】

后勤管理系统开发说明 开发语言&#xff1a;Java 框架&#xff1a;ssm JDK版本&#xff1a;JDK1.8 服务器&#xff1a;tomcat7 数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09; 数据库工具&#xff1a;Navicat11 开发软件&#xff1a;eclipse/myecli…

LLM 面试知识点——模型基础知识

1、主流架构 目前LLM(Large Language Model)主流结构包括三种范式,分别为Encoder-Decoder、Causal Decoder、Prefix Decode。对应的网络整体结构和Attention掩码如下图。 、 各自特点、优缺点如下: 1)Encoder-Decoder 结构特点:输入双向注意力,输出单向注意力。 代表…

【C语言】linux内核pci_save_state

一、中文注释 //include\linux\pci.h /* 电源管理相关的例程 */ int pci_save_state(struct pci_dev *dev);//drivers\pci\pci.c /*** pci_save_state - 在挂起前保存PCI设备的配置空间* dev: - 我们正在处理的PCI设备*/ int pci_save_state(struct pci_dev *dev) {int i;/* X…