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

Day 27 函数专题2 装饰器

昨天我们接触到了函数大部分的功能,然后在你日常ctrl点进某个复杂的项目,发现函数上方有一个@xxx,它就是装饰器

装饰器本质上是一个 Python 函数,它可以让其他函数或方法在不需要做任何代码修改的前提下增加额外功能。

--本质是如果让一个函数具备太多功能,那么他看起来就会比较乱,可读性比较差,如果把其中一部分相同甚至可以复用的功能用一个新的函数来调用,然后让2个函数同时实现,就会做到进一步封装了函数的一些用法,做到dry原则(don't repeat yourself),使函数更加具有可读性

所以装饰器本身就是函数中调用其他函数,实现先拆分函数,再合并函数的功能。

普通的函数

下面这个函数实现的是计算2到999999的所有质数(在大于 1 的自然数中,除了 1 和它自身外,不能被其他自然数整除的数),并且打印找到这些数需要的时间

在函数中通过time模块进行记时

会发现,这个time模块让整个代码逻辑很混乱,因为函数的主体是找质数,time模块是找质数的时间,如果可以time模块放在函数外,这样逻辑才清晰

import timedef is_prime(num): if num < 2:return Falsefor i in range(2,int(num**0.5) + 1):if num % i == 0:return Falsereturn Truedef prime_nums():begin_time = time.time()for i in range(2,1000000):is_prime(i) # 就不输出了,避免太多end_time = time.time()print(f"程序运行时间为{end_time - begin_time}秒")prime_nums()

运行结果: 程序运行时间为5.0821802616119385秒

装饰器函数

装饰器函数的参数是另一个函数,返回值也是一个函数;可以参考下方代码,看下优化在哪里。

import time# 定义一个装饰器
def display_time(func):def wrapper(): # 定义一个内部函数,在装饰器中wrapper函数是一个常用的函数名,并非强制,约定俗成的start_time = time.time()func()  # 直接调用原函数(无参数),这里的func()是指装饰器需要修饰的函数,在这里是prime_nums()end_time = time.time()print(f"执行时间: {end_time - start_time} 秒")return wrapper # return wrapper是返回函数对象,如果是return wrapper()则是立即执行wrapper函数def is_prime(num): if num < 2:return Falsefor i in range(2,int(num**0.5) + 1):if num % i == 0:return Falsereturn True@display_time #下面这个函数就是display_time的参数(fun)
def prime_nums():for i in range(2,1000000):is_prime(i) # 就不输出了,避免太多prime_nums()

运行结果:执行时间: 4.53002142906189 秒

逻辑上还是一样的,只不过这个把非重点函数的功能装饰起来了,使得我们看到的代码更加清晰明了。

进一步拓展装饰器实现复用

就是说一个装饰器可以被当作多个函数来用,其实就是传参数的问题,默认参数,或者一个、两个参数。

可以看到,上述这个写法的时候,prime_nums()没有传入参数,如果函数有参数,那么必须给外部函数传入参数,也就是需要给外部的装饰器函数传入参数。

那么装饰器函数是需要复用的,不同的内部函数传入的参数不同,那就需要装饰器可以传入可变参数来维持这个特性。这就是说到了我们昨天的可变参数

装饰器函数返回的是wrapper函数,所以,在调用装饰器函数的时候,返回的还是wrapper函数,而不是被修饰的函数。他是被修饰函数的外层函数,参数要大于等于被修饰函数的参数

今日作业

# 作业答案def logger(func):def wrapper(*args, **kwargs):  # 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 函数,观察日志输出

 总结

装饰器是 Python 里的语法糖,本质是高阶函数,能在不修改原函数代码和调用方式的前提下,为函数添加额外功能。

它接收一个函数作为参数,返回一个新函数。新函数会包裹原函数,在执行原函数前后添加新逻辑,比如日志记录、性能测试等。使用时,通过 `@` 符号将装饰器应用到目标函数上,提高代码复用性和可维护性,让代码更简洁优雅。

http://www.xdnf.cn/news/484453.html

相关文章:

  • 读取toml, 合并,生成新文件
  • Apollo Client 1.6.0 + @RefreshScope + @Value 刷新问题解析
  • volatile关键字详解
  • 淘宝商家层级存在流量上限怎么办,如何突破流量上限?
  • 梁文锋署名,DeepSeek-V3新论文揭秘:低成本大模型训练如何突破算力瓶颈?
  • 养生:健康生活的极简密码
  • P21-RNN-心脏病预测
  • blender中旋转模型,导入到threejs中带了旋转信息
  • Java与C/C++跨平台互操作深度解析:Project Panama技术实战
  • 一种应用非常广泛的开源RTOS(实时操作系统):nuttx
  • Spring Security vs Shiro vs Sa-Token
  • 2024年美团春招技术岗第一批笔试
  • 23、电网数据管理与智能分析 - 负载预测模拟 - /能源管理组件/grid-data-smart-analysis
  • nfs网络文件系统
  • 网站推荐(第四期)
  • 【C++ 基础数论】质数判断
  • Pageassist安装(ollama+deepseek-r1)
  • AI 赋能 Copula 建模:大语言模型驱动的相关性分析革新
  • 每周资讯 | 腾讯Q1财报:国内游戏业务收入同比增长24%;Tripledot 8亿美元收购AppLovin游戏业务
  • 十一、Hive JOIN 连接查询
  • IDEA中git对于指定文件进行版本控制
  • 架构与UML4+1视图
  • 基于PXIE 总线架构的Kintex UltraScale 系列FPGA 高性能数据预处理板卡
  • leetcode2749. 得到整数零需要执行的最少操作数-medium
  • ai agent(智能体)开发 python高级应用5:crawl4ai 如何建立一个全面的知识库 第一步找分类
  • Redis 五种类型基础操作(redis-cli + Spring Data Redis)
  • STM32F407VET6的HAL库使用CRC校验的思路
  • React文件上传组件封装全攻略
  • WEB安全--Java安全--shiro550反序列化漏洞
  • Linux——UDP/TCP协议理论