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

高频考点-Python中的装饰器的用法?

这是一个非常经典且重要的Python进阶知识点。

一句话理解:装饰器就是一个“给函数增加额外功能,但不修改函数内部代码”的工具。就像给手机套上手机壳——手机本身没变,但多了防摔功能。


1. 基础认知:一切皆函数

在讲装饰器前,先记住两点:

  • Python中,函数可以被当作参数传给另一个函数。

  • Python中,函数可以嵌套定义

2. 手动实现一个最简单的装饰器

假设你想知道一个函数运行了多长时间,但不想在每个函数里都写计时代码。

import time # 这是一个装饰器函数 def timer(func): def wrapper(*args, **kwargs): # *args, **kwargs 保证能接收任意参数 start = time.time() result = func(*args, **kwargs) # 真正执行原函数 end = time.time() print(f"函数 {func.__name__} 运行了 {end - start:.4f} 秒") return result return wrapper # 使用装饰器(语法糖 @) @timer def slow_function(): time.sleep(1) return "完成" # 调用时,完全无感知 print(slow_function()) # 输出:函数 slow_function 运行了 1.0002 秒 # 完成

背后原理:@timer等价于执行了slow_function = timer(slow_function),也就是把原函数替换成了wrapper


3. 带参数的装饰器(三层结构)

如果你的装饰器本身需要接收参数(比如指定超时时间),需要再包装一层:

def repeat(times): # 这是装饰器工厂,接收参数 def decorator(func): # 这是真正的装饰器 def wrapper(*args, **kwargs): for _ in range(times): result = func(*args, **kwargs) return result return wrapper return decorator @repeat(times=3) # 调用时带上参数 def say_hello(): print("Hello") say_hello() # 会打印 3 次 Hello

4. 保留原函数的元信息(重要!)

使用装饰器后,原函数的__name____doc__等会被wrapper覆盖,调试时会困惑。标准做法是加上functools.wraps

from functools import wraps def timer(func): @wraps(func) # 这一行把原函数的信息复制给 wrapper def wrapper(*args, **kwargs): # ... 计时逻辑 return func(*args, **kwargs) return wrapper

5. 类装饰器(用类来实现)

除了用函数,还可以用类来实现装饰器,通过__call__魔法方法:

class CountCalls: def __init__(self, func): self.func = func self.count = 0 def __call__(self, *args, **kwargs): self.count += 1 print(f"第 {self.count} 次调用") return self.func(*args, **kwargs) @CountCalls def test(): print("执行") test() # 第 1 次调用 test() # 第 2 次调用

6. 实际开发中最常用的场景

场景说明
登录校验检查用户是否登录,未登录则跳转
权限控制检查当前用户是否有权限执行该操作
日志记录自动记录函数的入参、返回值、异常
缓存(如@lru_cache对相同参数直接返回缓存结果
重试机制函数报错时自动重试 N 次
路由注册(Flask/FastAPI)@app.route('/')就是装饰器

7. 一个常见的坑:装饰器顺序

多个装饰器叠加时,执行顺序是自下而上(从靠近函数的开始):

@a @b @c def func(): pass # 实际执行顺序:func = a(b(c(func)))

8. 如果你刚接触,给你一个万能模板

以后写任何装饰器,直接套这个模板,不会出错:

from functools import wraps def my_decorator(func): @wraps(func) def wrapper(*args, **kwargs): # 在调用前做点什么 result = func(*args, **kwargs) # 在调用后做点什么 return result return wrapper

最后送你一个思考:装饰器本质上是“面向切面编程”(AOP)的一种实现,它把业务逻辑(核心功能)和辅助逻辑(日志、计时、校验)分离开,让代码更干净。

http://www.jsqmd.com/news/1201871/

相关文章:

  • 3步解锁你的智能终端:Warp主题定制与AI增强终极指南
  • 盐城结婚三金实测评测:四大品牌核心维度对比 - 招财兔数字员工
  • 欧米茄官方售后服务中心电话和详细地址实地考察报告多信源验证(2026年7月最新) - 欧米茄服务中心
  • TTKWidgetTools性能优化技巧:提升Qt界面渲染效率的5个关键点
  • 2026北京海淀卡地亚蒂芙尼回收哪家靠谱?高价专业门店推荐 - 全城热点
  • 深入理解Aave Protocol V2利率模型:如何最大化你的存款收益 [特殊字符]
  • 前端性能预算管理:首屏体积、FCP 与 LCP 的实用控制
  • 合肥包河区二手钻石变现实测,逸程正规门店当场全款结算避坑指南 - 逸程奢侈品回收中心
  • Paru深度解析:如何用Rust构建的AUR助手解决Arch Linux包管理难题
  • 万国中国官方售后服务中心|电话和完整地址权威信息公告(2026年7月更新) - 万国中国官方服务中心
  • 劳力士官方售后服务网点提供专业腕表维修保养服务权威公示(2026年7月最新) - 劳力士服务中心
  • Fiddler中文版安全测试指南:如何发现和修复Web应用漏洞
  • 2026年7月最新大连卡地亚官方售后客户服务热线与维修网点地址汇总 - 卡地亚官方售后中心
  • Easy-Query:Java/Kotlin高性能轻量级ORM框架完全指南
  • CANN/asc-devkit TensorTrait类型检查API
  • Aave Protocol V2开发者指南:从合约接口到集成实战
  • 消防远程联网监控平台系统之UI界面设计-设备信息查询界面
  • 多模型路由架构设计:根据任务复杂度分派不同模型
  • 南京良庆美度手表回收 2026,今日最新行情快速变现渠道 - 禹竞奢收行
  • datascience与Jupyter Notebook集成:提升教学效率的5个技巧
  • MPL_ROS与ROS 2迁移指南:从ROS Kinetic到ROS 2 Foxy的完整迁移方案
  • 擅长互联网行业的猎头公司哪家好?哪家猎头公司擅长互联网行业的中高端人才招聘? - 榜单推荐
  • 2026年7月徐州装修装饰市场优选服务商深度解析 - 品牌鉴赏官2026
  • 欧米茄官方售后服务中心全部网点地址及24小时热线实地考察报告+多信源验证(2026年7月更新) - 欧米茄官方服务中心
  • Rufus终极指南:免费开源工具如何彻底改变USB启动盘制作体验
  • 盘点崂山城阳回收门店,同城上门当场结算闲置包 - 生活时报
  • OptiScaler技术问题排查实战指南:完整解决方案与深度优化
  • 2026年南京靠谱全屋装修公司盘点:优质选择与专业解析 - 品牌鉴赏官2026
  • 2026华东流体控胶设备选购解析苏州本地点胶制造企业与高粘度压盘供料设备合作方筛选要点 - 栗子测评
  • 计算机毕业设计之校园论坛的设计和实现