Python之装饰器-无参装饰器
Python之装饰器-无参装饰器
装饰器介绍
1. 为何要用装饰器
- Python 中的装饰器是一种语法糖,可以在运行时,动态的给函数或类添加功能。
- 装饰器本质上是一个函数,使用 @ + 函数名就是可实现绑定给函数的第二个功能 。
- 将一些通用的、特定函数的功能抽象成一个装饰器,可以重复利用这些功能
2. 什么是装饰器
- “装饰”代指为被装饰对象添加新的功能,“器”代指器具/工具
- 装饰器的作用:就是在不修改被装饰对象源代码和调用方式的前提下为被装饰对象添加额外的功能。
- 装饰器使用场景:插入日志、性能测试、事务处理、缓存、权限校验
- 可以调用的有:函数、方法、类
- 函数装饰器分为:无参装饰器和有参装饰,二者都是使用都是需要【名称空间+函数嵌套+闭包+函数对象的组合知识】
- 使用“@”符号定义装饰器,前提是需要有一个函数作为工具然后被“@”装饰到其他函数头上,为这个函数添加功能
无参装饰器
- @符号后是一个函数
- 虽然是无参装饰器,但是@后的函数本质上是单参函数
def add(x, y):print(add.__name__, x, y)return x + yadd(4, 5)# 此函数记录了,调用了add函数,x和y的值是什么
# 返回结果:add 4 5
# 返回结果:9
import time # 时间底层模块
print('------')
time.sleep(10)
print('******')# 导入time模块,执行第1个print后,time.sleep(10) 休眠10秒,然后输出第2个print
# 返回结果:------
# 返回结果:******
import datetime # 导入datetime模块start = datetime.datetime.now() # 设置start,获取当前时间# 导入datetime模块
end = datetime.datetime.now() # 设置end,获取当前时间# end变量在下一个代码块中执行,稍微等几秒错开时间。
start, end # 记录的两个时间戳,用于记录开始时间和结束时间
# 返回结果:(datetime.datetime(2024, 3, 23, 11, 4, 2, 337816), datetime.datetime(2024, 3, 23, 11, 4, 4, 518772))
(end - start).total_seconds() # total.seonds 总秒数# end 减去 start 获取运行的秒数
# 返回结果:2.180956
def add(x, y):#print(add.__name__, x, y) # 这个只能记录add,sub呢?#time.sleep(2) # 修秒2秒return x + ydef logger(fn):ret = fn(4, 5)return retlogger(add)# base版,基于这版,增加功能、
# 返回结果:9
def add(x, y):#print(add.__name__, x, y) # 这个只能记录add,sub呢?#time.sleep(2)return x + ydef logger(fn, x, y):ret = fn(x, y)return retlogger(add, 4, 5)# 返回结果:9
def add(x, y):#print(add.__name__, x, y) # 你这个只能记录add,sub呢?#time.sleep(2)return x + ydef logger(fn, x, y):print(fn.__name__, x, y) # 增加记录值ret = fn(x, y)return retlogger(add, 4, 5)# 返回结果:add 4 5
# 返回结果:9
def add(x, y):#mylog(add.__name__, x, y) # 你这个只能记录add,sub呢?#time.sleep(2)return x + ydef sub(x, y): # 可以用于多个函数return x - ydef logger(fn, x, y):print(fn.__name__, x, y) # 增加记录值ret = fn(x, y)return retlogger(add, 4, 5)
logger(sub, 5, 6)# 返回结果:add 4 5
# 返回结果:sub 5 6
# 返回结果:-1
def add(x, y):#mylog(add.__name__, x, y) # 你这个只能记录add,sub呢?#time.sleep(2)return x + ydef sub(x, y, z): # 可以用于多个函数return x - y - zdef logger(fn, *args, **kwargs): # 接受关键字传参,位置传参。print(fn.__name__, args, kwargs) # 增加记录值print('执行前可以做的事情,增强')ret = fn(*args, **kwargs)print('执行后可以做的事情,增强')return retlogger(add, 4, y=8)
logger(sub, 5, 6, z=7)# 返回结果:add (4,) {'y': 8}
# 返回结果:执行前可以做的事情,增强
# 返回结果:执行后可以做的事情,增强
# 返回结果:sub (5, 6) {'z': 7}
# 返回结果:执行前可以做的事情,增强
# 返回结果:执行后可以做的事情,增强
# 返回结果:-8
def add(x, y):#mylog(add.__name__, x, y) # 你这个只能记录add,sub呢?#time.sleep(2)return x + ydef sub(x, y, z): # 可以用于多个函数return x - y - zdef logger(fn):def inner(*args, **kwargs):print(fn.__name__, args, kwargs) # 增加记录值print('执行前可以做的事情,增强')ret = fn(*args, **kwargs)print('执行后可以做的事情,增强')return retreturn innerlogger(add)(4, y=8)
#logger(sub, 5, 6, z=7)# 返回结果:add (4,) {'y': 8}
# 返回结果:执行前可以做的事情,增强
# 返回结果:执行后可以做的事情,增强
# 返回结果:12
def add(x, y):#time.sleep(2)return x + ydef sub(x, y, z): # 可以用于多个函数return x - y - zdef logger(fn):def inner(*args, **kwargs):print('执行前可以做的事情,增强', fn.__name__, args, kwargs)ret = fn(*args, **kwargs)print('执行后可以做的事情,增强')return retreturn innerlogger(add)(4, y=8)
#logger(sub, 5, 6, z=7)# 返回结果:执行前可以做的事情,增强 add (4,) {'y': 8}
# 返回结果:执行后可以做的事情,增强
# 返回结果:12
def add(x, y):#time.sleep(2)return x + ydef sub(x, y, z): # 可以用于多个函数return x - y - zdef logger(fn): # fn adddef inner(*args, **kwargs):print('执行前可以做的事情,增强', fn.__name__, args, kwargs)ret = fn(*args, **kwargs) # fn(4, y=8) add(4, y=8)print('执行后可以做的事情,增强')return retreturn innert = logger(add) # t = inner
print(t(4, y=8)) # inner(4, y=8)# 返回结果:执行前可以做的事情,增强 add (4,) {'y': 8}
# 返回结果:执行后可以做的事情,增强
# 返回结果:12
def add(x, y):#time.sleep(2)return x + ydef logger(fn): # fn adddef inner(*args, **kwargs):print('执行前可以做的事情,增强', fn.__name__, args, kwargs)ret = fn(*args, **kwargs) # fn(4, y=8) add(4, y=8)print('执行后可以做的事情,增强')return retreturn inner#t = logger(add) # t = inner
#print(t(4, y=8)) # inner(4, y=8)add = logger(add)
print(add(4, 5))# 返回结果:执行前可以做的事情,增强 add (4, 5) {}
# 返回结果:执行后可以做的事情,增强
# 返回结果:9

def add(x, y):#time.sleep(2)return x + ydef logger(fn): # fn adddef inner(*args, **kwargs):print('执行前可以做的事情,增强', fn.__name__, args, kwargs)ret = fn(*args, **kwargs) # fn(4, y=8) add(4, y=8)print('执行后可以做的事情,增强')return retreturn inner#t = logger(add) # t = inner
#print(t(4, y=8)) # inner(4, y=8)
print(hex(id(add))) # 打印add的id值
add = logger(add)
print(add(4, 5))
print(add.__closure__) # 查看add的closure中记录闭包# 返回结果:0x10954fd80
# 返回结果:执行前可以做的事情,增强 add (4, 5) {}
# 返回结果:执行后可以做的事情,增强
# 返回结果:9
# 返回结果:(<cell at 0x1083e3d90: function object at 0x10954fd80>,)
def logger(fn): # fn adddef inner(*args, **kwargs):print('执行前可以做的事情,增强', fn.__name__, args, kwargs)ret = fn(*args, **kwargs) # fn(4, y=8) add(4, y=8)print('执行后可以做的事情,增强')return retreturn inner@logger # 装饰器 #等价式, add = logger(add) # logger应该等效为单参函数
def add(x, y):#time.sleep(2)return x + y#t = logger(add) # t = inner
#print(t(4, y=8)) # inner(4, y=8)
#add = logger(add)
print(add(4, 5))# @装饰器语法,@标识符,把这一行下面一行的def定义的标识符作为其实参传入,返回值覆盖了下面这个标识符
# 返回结果:执行前可以做的事情,增强 add (4, 5) {}
# 返回结果:执行后可以做的事情,增强
# 返回结果:9
def logger(fn): def inner(*args, **kwargs):print('执行前可以做的事情,增强', fn.__name__, args, kwargs)ret = fn(*args, **kwargs) print('执行后可以做的事情,增强')return retreturn inner@logger # 装饰器 #等价式, add = logger(add) # logger应该等效为单参函数
def add(x, y):#time.sleep(2)return x + yprint(add(4, 5)) # 非侵入代码,完成了功能,并且好像从来没有装饰过一样
print(add.__name__) #add实际是inner# 返回结果:执行前可以做的事情,增强 add (4, 5) {}
# 返回结果:执行后可以做的事情,增强
# 返回结果:9
# 返回结果:inner
def logger(wrapped): def wrapper(*args, **kwargs):print('执行前可以做的事情,增强', wrapped.__name__, args, kwargs)ret = wrapped(*args, **kwargs) print('执行后可以做的事情,增强')return retreturn wrapper@logger # 装饰器 #等价式, add = logger(add) # logger应该等效为单参函数
def add(x, y):#time.sleep(2)return x + yprint(add(4, 5)) # 非侵入代码,完成了功能,并且好像从来没有装饰过一样
print(add.__name__)# 返回结果:执行前可以做的事情,增强 add (4, 5) {}
# 返回结果:执行后可以做的事情,增强
# 返回结果:9
# 返回结果:wrapper
def logger(wrapped): def wrapper(*args, **kwargs):start = datetime.datetime.now()ret = wrapped(*args, **kwargs) delta = (datetime.datetime.now() - start).total_seconds()print("{} tooks {}s.".format(wrapped.__name__, delta))return retreturn wrapper@logger # 装饰器 #等价式, add = logger(add) # logger应该等效为单参函数
def add(x, y):time.sleep(2)return x + yprint(add(4, 5)) # 非侵入代码,完成了功能,并且好像从来没有装饰过一样
print(add.__name__) # 返回结果:add tooks 2.002051s.
# 返回结果:9
# 返回结果:wrapper
相关文章:
Python之装饰器-无参装饰器
Python之装饰器-无参装饰器 装饰器介绍 1. 为何要用装饰器 Python 中的装饰器是一种语法糖,可以在运行时,动态的给函数或类添加功能。装饰器本质上是一个函数,使用 函数名就是可实现绑定给函数的第二个功能 。将一些通用的、特定函数的功…...
音视频实战--音视频编码
1、查找所需的编码器–avcodec_find_encoder或avcodec_find_encoder_by_name 音频编码和视频编码流程基本相同,使用音频编码器则可以编码音频数据,使用视频编码器则可以编码视频数据。 /* 指定的编码器 ID 查找对应的编码器。可以通过这个函数来获取特…...
【黄金手指】windows操作系统环境下使用jar命令行解压和打包Springboot项目jar包
一、背景 项目中利用maven将Springboot项目打包成生产环境jar包。名为 prod_2024_1.jar。 需求是 修改配置文件中的某些参数值,并重新发布。 二、解压 jar -xvf .\prod_2024_1.jar释义: 这段命令是用于解压缩名为"prod_2024_1.jar"的Java归…...
React【Day1】
B站视频链接 一、React介绍 React由Meta公司开发,是一个用于 构建Web和原生交互界面的库 React的优势 相较于传统基于DOM开发的优势 组件化的开发方式不错的性能 相较于其它前端框架的优势 丰富的生态跨平台支持 React的市场情况 全球最流行,大…...
MNN 执行推理(九)
系列文章目录 MNN createFromBuffer(一) MNN createRuntime(二) MNN createSession 之 Schedule(三) MNN createSession 之创建流水线后端(四) MNN Session 之维度计算(五…...
算法公式汇总
文章目录 三角函数定义式诱导公式平方关系两角和与差的三角函数积化和差公式和差化积公式倍角公式半角公式万能公式其他公式反三角函数恒等式 三角函数定义式 三角函数 定义式 余切: c o t A 1 t a n A \text { 余切:} \ cotA \frac{1}{tanA} 余切&a…...
c语言管理课程信息系统
定制魏:QTWZPW,获取更多源码等 目录 题目要求 数据结构 函数设计 结构设计 管理员功能: 学生功能: 效果展示 总结 主函数代码 题目要求 管理课程信息系统,允许管理员和学生执行不同的操作。管理员可以添加、浏览、查询、删除、修改和排序课程信息。学生可以…...
大模型在天体物理学研究中的辅助作用与案例分析
大模型在天体物理学研究中的辅助作用与案例分析 1. 背景介绍 天体物理学是研究宇宙中各种天体的物理性质和运动规律的科学。随着观测技术的进步,天体物理学家们获得了大量的数据,这些数据往往具有高维度、非线性、非平稳等特点,给传统的数据…...
洛谷_P1873 [COCI 2011/2012 #5] EKO / 砍树_python写法
P1873 [COCI 2011/2012 #5] EKO / 砍树 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) n, m map(int,input().split())data list(map(int,input().split())) h 0 def check(mid):h 0for i in data:if i>mid:h (i-mid)if h < m:return Trueelse:return Falsel 0 r …...
Android_NDK调试
第一步: 链接log动态库 在Android.mk文件中添加 LOCAL_LDLIBS -llog 注意:一定要在 include $(BUILD_SHARED_LIBRARY) 之上添加,因为当执行到这句话的时候就表示所有的lib动态库已经加载完毕了,所以当你在这句代码之后再添加…...
全量知识系统 概要设计(SmartChat回复)
以下是根据我给出的 系统概要 “提要和纪要”,SmartChat给出的概要设计。我给出的“提要和纪要”可参考链接: https://blog.csdn.net/ChuanfangChen/article/details/136861822 -------------------------------- 概要设计文档 1. 简介 全量知识系统…...
一、SpringBoot基础搭建
本教程主要给初学SpringBoot的开发者,通过idea搭建单体服务提供手把手教学例程,主要目的在于理解环境的搭建,以及maven模块之间的整合与调用 源码:jun/learn-springboot 以商城项目为搭建例子,首先计划建1个父模块&…...
some/ip CAN CANFD
关于SOME/IP的理解 在CAN总线的车载网络中,通信过程是面向信号的 当ECU的信号的值发生了改变,或者发送周期到了,就会发送消息,而不考虑接收者是否需要,这样就会造成总线上出现不必要的信息,占用了带宽 …...
HTTP Header Fields
HTTP(超文本传输协议)中包含多种类型的头部字段(Header Fields),以下是常见的HTTP头部字段及其作用: ### 通用头字段(General Header Fields) - **Cache-Control**: 控制缓存行为&a…...
基于FPGA的FFT图像滤波设计
1.FFT滤波算法介绍 FFT滤波就是通过傅里叶运算将图像转换到频域空间,然后在频域中对图像进行处理,最后将处理后的图像通过傅里叶逆运算将图像转会到时域空间。 在频域空间中,我们能够更好的对图像的噪声进行分析,然后找出相关规律…...
WPF 立体Border
WPF 立体Border ,用来划分各个功能区块 在资源文件中,添加如下样式代码: <Style x:Key"BaseBorder" TargetType"Border"><Setter Property"Background" Value"White" /><Setter Prop…...
java.lang.ClassNotFoundException: kotlin.jvm.internal.Intrinsics
今天在使用springBoot连接influxdb报错 java.lang.ClassNotFoundException: kotlin.jvm.internal.Intrinsics 详细报错如下,提出我们缺少一个依赖 原因是由于创建influxdb客户端缺少Kotlin运行时库 解决办法就是 1.显示的添加okhttp的依赖 <dependency>…...
代码随想录(day8)——字符串
Leetcode.344 反转字符串: 344. 反转字符串 - 力扣(LeetCode) 原理过于简单,没什么好说的,直接给出代码: class Solution { public:void reverseString(vector<char>& s) {int end s.size()-1…...
JavaScript 权威指南第七版(GPT 重译)(二)
第四章:表达式和运算符 本章记录了 JavaScript 表达式以及构建许多这些表达式的运算符。表达式 是 JavaScript 的短语,可以 评估 以产生一个值。在程序中直接嵌入的常量是一种非常简单的表达式。变量名也是一个简单表达式,它评估为分配给该变…...
【python_往企业微信群中发送文件】
python_往企业微信群中发送文件 这个是用企业微信群机器人的功能,没有用到后台应用。群机器人 #-*- coding:utf-8-* import requests#类型:voice,file file_type"file" file_path"D:\desktop\不过.jpg" webhookkey"xxxx"#…...
从零实现富文本编辑器#5-编辑器选区模型的状态结构表达
先前我们总结了浏览器选区模型的交互策略,并且实现了基本的选区操作,还调研了自绘选区的实现。那么相对的,我们还需要设计编辑器的选区表达,也可以称为模型选区。编辑器中应用变更时的操作范围,就是以模型选区为基准来…...
Cesium1.95中高性能加载1500个点
一、基本方式: 图标使用.png比.svg性能要好 <template><div id"cesiumContainer"></div><div class"toolbar"><button id"resetButton">重新生成点</button><span id"countDisplay&qu…...
Opencv中的addweighted函数
一.addweighted函数作用 addweighted()是OpenCV库中用于图像处理的函数,主要功能是将两个输入图像(尺寸和类型相同)按照指定的权重进行加权叠加(图像融合),并添加一个标量值&#x…...
对WWDC 2025 Keynote 内容的预测
借助我们以往对苹果公司发展路径的深入研究经验,以及大语言模型的分析能力,我们系统梳理了多年来苹果 WWDC 主题演讲的规律。在 WWDC 2025 即将揭幕之际,我们让 ChatGPT 对今年的 Keynote 内容进行了一个初步预测,聊作存档。等到明…...
spring:实例工厂方法获取bean
spring处理使用静态工厂方法获取bean实例,也可以通过实例工厂方法获取bean实例。 实例工厂方法步骤如下: 定义实例工厂类(Java代码),定义实例工厂(xml),定义调用实例工厂ÿ…...
Robots.txt 文件
什么是robots.txt? robots.txt 是一个位于网站根目录下的文本文件(如:https://example.com/robots.txt),它用于指导网络爬虫(如搜索引擎的蜘蛛程序)如何抓取该网站的内容。这个文件遵循 Robots…...
关键领域软件测试的突围之路:如何破解安全与效率的平衡难题
在数字化浪潮席卷全球的今天,软件系统已成为国家关键领域的核心战斗力。不同于普通商业软件,这些承载着国家安全使命的软件系统面临着前所未有的质量挑战——如何在确保绝对安全的前提下,实现高效测试与快速迭代?这一命题正考验着…...
Unsafe Fileupload篇补充-木马的详细教程与木马分享(中国蚁剑方式)
在之前的皮卡丘靶场第九期Unsafe Fileupload篇中我们学习了木马的原理并且学了一个简单的木马文件 本期内容是为了更好的为大家解释木马(服务器方面的)的原理,连接,以及各种木马及连接工具的分享 文件木马:https://w…...
【7色560页】职场可视化逻辑图高级数据分析PPT模版
7种色调职场工作汇报PPT,橙蓝、黑红、红蓝、蓝橙灰、浅蓝、浅绿、深蓝七种色调模版 【7色560页】职场可视化逻辑图高级数据分析PPT模版:职场可视化逻辑图分析PPT模版https://pan.quark.cn/s/78aeabbd92d1...
基于 TAPD 进行项目管理
起因 自己写了个小工具,仓库用的Github。之前在用markdown进行需求管理,现在随着功能的增加,感觉有点难以管理了,所以用TAPD这个工具进行需求、Bug管理。 操作流程 注册 TAPD,需要提供一个企业名新建一个项目&#…...
