当前位置: 首页 > news >正文

day 40 打卡-装饰器

装饰器本质上是一个python 函数,它可以让其他函数或者方法在不需要做任何代码修改的前提下增加额外功能。---本质是如果让一个函数具备太多功能,那么它看起来很久就会比较乱,可读性比较差,如果把器中一部分相同甚至可以复用的功能用一个新的函数来调用,然后让2个函数同时实现,就会做到。
1、进一步封装了函数的一些用法,做到dry 原则(don't repeat yourself)
2、使函数更加具有可读性。
所以装饰器本身就是函数,实现先拆分函数,再合并函数的功能。
普通的函数
下面的函数实现的是计算2到9999的所有质数,并且打印找到这些数需要的时间
1、定义一个判断是否为质数
2、定义一个函数,循环2到9999的数,通过判断质数函数来筛选每个数
3、在函数中通过time模块计时
会发现,这个time 模块让整个代码逻辑混乱,因为函数的主体是找质数,time模块是找质数的时间,如果可以让time 模块放在函数外,这样逻辑才清晰。import time
def is_prime(num):if num <2:return Falsefor i in range(2,num):if num % i == 0:return Falsereturn True
def prime_nums():t1=time.time()for i in range(2,10000):if is_prime(i):print(i)t2=time.time()print(t2-t1)
prime_nums()
装饰器函数
import time
# 定义一个装饰器
def display_time(func):def wrapper(*args,**kwargs):start = time.time()func(*args,**kwargs)end = time.time()print(end-start)return wrapper
装饰器的本质是一个高阶函数,它接收一个函数作为参数,并返回一个新函数来替代原函数,这个新函数需要:
1、保留原函数的调用方式(参数和返回值)
2、在原函数执行前添加额外逻辑
因此,我们需要在装饰器内部定义一个新的函数来实现这些功能。
# 继续定义判断质数的函数
def is_prime(num):if num <2:return Falseelif num ==2:return Trueelse:for i in range(2,num):if num % i ==0:return Falsereturn True
# 装饰器的标准写法
@display_time
def  prime_nums():for i in range(2,100):if is_prime(i):print(i)
prime_nums()
def prime_nums():...# 函数体
prime_nums=display_time(prime_nums)
装饰器的执行流程为:
1、定义装饰器函数 display_time   它接收一个函数func作为参数,并返回wrapper 函数。
2、定义被装饰函数prime_nums:此时prime_nums是一个普通函数的对象。
3、应用装饰器:python 自动将prime_nums作为参数传递给display_time ,即执行display_time(prime_nums)
4、替换原函数:display_time(prime_nums)返回wrapper 函数,将其赋值给prime_nums ,即prime_nums=wrapper也就是说装饰后,原函数名指向wrapper ,而 非原始函数。
当你调用prime_nums()时,实际上执行的是wrapper(),他会:
1、记录开始时间
2、调用func 
3、记录结束时间并打印
这种等价的设计,会让初学者搞不懂为啥突然可以采取这种优雅的 写法,类似的写法有很多,在python 中叫做语法糖:通过规范的语法来让代码更加优美简洁,比如列表推导式也是。
可以吧@ 理解为语法糖操作,实际上并非是@ 装饰器,而是@装饰器+下一行的代码,二者一个整体。进一步扩展装饰器实现复用
可以看到,上述这个写法的时候,prime_nums() 没有传入参数,如果函数有参数,那么必须给外部函数传入参数,也就是需要给外部的装饰器函数传入参数。
那么装饰器函数是需要复用的,不同的内部函数传入的参数不同,那久需要装饰器可以传入可变参数来维持这个特性。这就是说到了我们昨天的可变参数。
装饰器函数返回的是wrapper 函数,所以,在调用装饰器函数的时候,返回的还是wrapper 函数,而不是被修饰的函数。他是被修饰的函数的外层函数,参数要大于等于被修饰函数的参数。
import time
def display_time(func):"""支持任意参数的时间统计装饰器"""def wrapper(*args,**kwargs):t1=time.time()result= func(*args,**kwargs)t2=time.time()print(f"{func.__name__} 运行时间: {t2-t1} 秒")return resultreturn wrapper
@display_time
def add(a,b):return a+b
add(3,5)
最后一个tips:注意下内部函数有无返回值
注意到之前被修饰的函数在无参情况下,wrapper里面只有func(),现在是result=func(*args,**kwargs)以及加上了return result今日作业def logger(func):def wrapper(*args,**kwargs):print(f"调用函数 {func.__name__},参数为 {args} {kwargs}")result=func(*args,**kwargs)print(f"函数 {func.__name__} 返回值为 {result}")return resultreturn wrapper
@logger
def multiply (a,b):return a*b
multiply(2,3)
multiply(a=2,b=3)

@浙大疏锦行

http://www.lryc.cn/news/604321.html

相关文章:

  • 让科技之光,温暖银龄岁月——智绅科技“智慧养老进社区”星城国际站温情纪实
  • 品牌侵权查询怎么查?跨境电商怎样查品牌是否侵权?
  • 笔记本电脑开机慢系统启动慢怎么办?【图文详解】win7/10/11开机慢
  • Apache Ignite 中如何配置和启用各类监控指标
  • T113-i Linux系统完整构建指南:从SDK开箱到内核镜像量产烧录全流程
  • 计算机网络1-3:三种交换方式
  • 【38】WinForm入门到精通 ——WinForm平台为AnyCPU 无法切换为x64,也无法添加 x64及其他平台
  • 15.10 单机8卡到千卡集群!DeepSpeed实战调参手册:A100训练效率翻倍,百万成本优化实录
  • 文心大模型4.5开源:国产AI的破茧时刻与技术普惠实践
  • 工作笔记-----FreeRTOS中的lwIP网络任务为什么会让出CPU
  • 24串高边BMS全套设计方案!
  • 51单片机入门:数码管原理介绍及C代码实现
  • YOLO融合MogaNet中的ChannelAggregationFFN模块
  • 基于 Python 开发的信阳市天气数据可视化系统源代码+数据库+课程报告
  • 基于 Hadoop 生态圈的数据仓库实践 —— OLAP 与数据可视化(三)
  • C++ Qt网络编程实战:跨平台TCP调试工具开发
  • 基于 Hadoop 生态圈的数据仓库实践 —— OLAP 与数据可视化(四)
  • 北京理工大学医工交叉教学实践分享(1)|如何以实践破解数据挖掘教学痛点
  • 使用es实现全文检索并且高亮显示
  • ArcGIS以及ArcGIS Pro如何去除在线地图制作者名单
  • 6.Origin2021如何绘制Y轴截断图?
  • 技术速递|GitHub Copilot 的 Agent 模式现已全面上线 JetBrains、Eclipse 和 Xcode!
  • 2025Nacos安装Mac版本 少走弯路版本
  • 知识速查大全:python面向对象基础
  • 手撕设计模式——智能家居之外观模式
  • iOS 签名证书与上架流程详解,无 Mac 环境下的上架流程
  • 专题:2025机器人产业技术图谱与商业化指南|附130+份报告PDF、数据汇总下载
  • 2025光伏自动化破局!艾利特机器人用“智能感知+柔性控制”领跑行业
  • Scala实现常用排序算法
  • USB电源原理图学习笔记