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

Python @装饰器用法详解

当然!让我用更详细的方式重新解释自定义装饰器。

装饰器的基本概念

装饰器本质上是一个函数,它接受一个函数作为参数,并返回一个新的函数。它"装饰"或"包装"原始函数,在不修改原函数代码的情况下添加新功能。

简单比喻

想象装饰器就像给你的函数"穿上一件外套":

  • 原始函数是"身体"
  • 装饰器是"外套"
  • 穿上外套后,函数有了新功能,但核心功能不变

逐步理解

第一步:没有装饰器的版本

def greet():print("Hello!")# 如果我们想在每次调用greet时记录时间
import timedef greet_with_timing():start = time.time()greet()  # 调用原始函数end = time.time()print(f"函数执行了 {end-start:.2f} 秒")greet_with_timing()

这样写的问题:每次都要手动包装,代码重复。

第二步:手动创建装饰器

def timer_decorator(func):def wrapper():start = time.time()func()  # 调用原始函数end = time.time()print(f"{func.__name__} 执行了 {end-start:.2f} 秒")return wrapper# 手动应用装饰器
greet = timer_decorator(greet)
greet()  # 现在会自动计时

第三步:使用@语法糖

@timer_decorator  # 这行等同于:greet = timer_decorator(greet)
def greet():print("Hello!")@timer_decorator
def say_goodbye():print("Goodbye!")greet()      # 自动计时
say_goodbye() # 自动计时

更实用的例子

1. 日志记录装饰器

def logger(func):def wrapper(*args, **kwargs):print(f"开始执行函数: {func.__name__}")print(f"参数: {args} {kwargs}")result = func(*args, **kwargs)print(f"函数 {func.__name__} 执行完成,返回值: {result}")return resultreturn wrapper@logger
def add(a, b):return a + b@logger
def multiply(x, y):return x * yadd(3, 5)
# 输出:
# 开始执行函数: add
# 参数: (3, 5) {}
# 函数 add 执行完成,返回值: 8multiply(4, 6)
# 输出:
# 开始执行函数: multiply
# 参数: (4, 6) {}
# 函数 multiply 执行完成,返回值: 24

2. 权限验证装饰器

def login_required(func):def wrapper(user, *args, **kwargs):if user.get('is_authenticated', False):return func(user, *args, **kwargs)else:return "请先登录!"return wrapper@login_required
def view_profile(user):return f"欢迎 {user['username']} 查看个人资料"# 测试
user1 = {'username': 'Alice', 'is_authenticated': True}
user2 = {'username': 'Bob', 'is_authenticated': False}print(view_profile(user1))  # 欢迎 Alice 查看个人资料
print(view_profile(user2))  # 请先登录!

3. 重试装饰器

def retry(max_attempts=3):def decorator(func):def wrapper(*args, **kwargs):for attempt in range(max_attempts):try:return func(*args, **kwargs)except Exception as e:print(f"第{attempt+1}次尝试失败: {e}")if attempt == max_attempts - 1:raisereturn Nonereturn wrapperreturn decorator@retry(max_attempts=3)
def unstable_connection():import randomif random.random() < 0.7:  # 70%概率失败raise ConnectionError("连接失败")return "连接成功!"# 多次运行这个函数,观察重试机制
result = unstable_connection()
print(result)

装饰器的工作原理

# 理解这个等价关系很重要:
@decorator
def my_function():pass# 完全等同于:
def my_function():pass
my_function = decorator(my_function)

为什么要用装饰器?

  1. 代码复用:一次编写,多处使用
  2. 关注点分离:核心逻辑和附加功能分开
  3. 不修改原代码:保持原始函数的纯净
  4. 灵活组合:可以叠加多个装饰器
@logger
@timer_decorator
@login_required
def complex_operation(user, data):# 这个函数同时拥有了日志、计时、权限验证功能return "操作完成"

总结

自定义装饰器就是创建一个包装函数,它:

  • 接受一个函数作为输入
  • 添加一些额外功能
  • 返回一个新的函数(通常调用原始函数)
  • 使用@装饰器名语法来应用

这样你就能在不修改原函数的情况下,给函数添加各种通用功能!


完全正确!你的理解非常准确!

@timer_decorator
def greet():print("Hello!")

确实完全等同于:

def greet():print("Hello!")
greet = timer_decorator(greet)

验证这个等价关系

让我们用代码来验证:

def timer_decorator(func):def wrapper():print("开始计时...")result = func()print("计时结束")return resultreturn wrapper# 方法1:使用@语法
@timer_decorator
def greet1():print("Hello!")# 方法2:手动赋值
def greet2():print("Hello!")
greet2 = timer_decorator(greet2)# 测试两个函数
print("=== greet1 ===")
greet1()print("\n=== greet2 ===")
greet2()print(f"\n两个函数相同吗? {greet1 == greet2}")  # 应该是 False,因为它们是不同的包装函数实例
print(f"但功能相同吗?让我们看看输出...")

输出结果:

=== greet1 ===
开始计时...
Hello!
计时结束=== greet2 ===
开始计时...
Hello!
计时结束两个函数相同吗? False
但功能相同吗?让我们看看输出...

深入理解装饰器的执行时机

def my_decorator(func):print(f"装饰器被执行了!要装饰的函数是: {func.__name__}")def wrapper():print("包装函数被调用")return func()return wrapperprint("=== 定义阶段 ===")
@my_decorator
def my_function():print("原始函数被调用")print("\n=== 调用阶段 ===")
my_function()

输出:

=== 定义阶段 ===
装饰器被执行了!要装饰的函数是: my_function=== 调用阶段 ===
包装函数被调用
原始函数被调用

关键点:

  • 装饰器在函数定义时立即执行,而不是在函数调用时
  • @decorator 这行代码在模块加载时就会运行
  • 它实际上调用了 decorator 函数,并把被装饰的函数作为参数传递

为什么要有@语法糖?

如果没有@语法,代码会变得很冗长:

# 没有@语法
def func1(): pass
func1 = decorator1(func1)def func2(): pass  
func2 = decorator2(func2)def func3(): pass
func3 = decorator3(func3)# 使用@语法
@decorator1
def func1(): pass@decorator2
def func2(): pass@decorator3
def func3(): pass

@语法让代码:

  • 更清晰:装饰器紧挨着函数定义
  • 更易读:一眼就能看出函数被装饰了
  • 更符合直觉:装饰在"上面",就像给函数"戴帽子"

所以你的理解完全正确!@decorator 就是 Python 提供的一种语法糖,让装饰器的使用更加简洁美观。

http://www.dtcms.com/a/449690.html

相关文章:

  • 模电基础:差分放大电路
  • SSM--day2--Spring(二)--核心容器注解开发Spring整合
  • 正规的装饰行业网站建设公司北京新浪网站制作公司
  • Verilog可综合电路设计:重要语法细节指南
  • 力扣hot100做题整理(41-50)
  • 大连模板网站制作公司电话创业平台有哪些
  • 实战指南:文生图模型 Animagine XL 4.0
  • Linux中fcntl系统调用的实现
  • 网站搭建大型公司框架网站模板
  • RAG开发
  • 季度优选策略:年化472%,回撤 8%,夏普5.48,卡玛比率61.55
  • 直播网站建设费用做音乐的网站设计
  • 基于springboot的蜗牛兼职网的设计与实现
  • 网站管理系统是什么wordpress 分类浏览
  • Docker(五)—— Docker Compose 一键搭建 LNMP 架构并部署 WordPress
  • uniapp开发的后台系统
  • 深圳网站营销公司网站做实名验证
  • python编写AI生常用匡架及使用指令集
  • GridView 中使用重绘边界的实用建议
  • FPGA学习篇——Verilog学习之计数器的实现
  • 网站建设万网浙江建设网站公司
  • 刷粉网站推广快点商标设计注册
  • MySQL 配置管理与日志系统完全指南:从基础到高级优化
  • Leecode hot100 - 279. 完全平方数
  • 珠宝营销型网站设计珠海做网站及推广
  • 视频原创度检测算法对比
  • Spring MVC 九大组件源码深度剖析(九):FlashMapManager - 重定向数据的守护者
  • 网站设计上市公司继续浏览此网站(不推荐)
  • The “Launch” - 价值交付与灰度发布
  • 做网站公司(信科网络)网站开发外包报价