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

2.1 python装饰器基础:从语法糖到高阶函数

2.1 装饰器基础:从语法糖到高阶函数

  • 2.1 装饰器基础:从语法糖到高阶函数
      • 2.1 装饰器基础:从语法糖到高阶函数
        • 高阶函数:装饰器的基石
        • 装饰器语法糖:优雅的简写
        • 深入理解装饰器执行流程
        • 处理带参数的函数
        • 保留原函数的元信息
        • 装饰器的实际应用场景

2.1 装饰器基础:从语法糖到高阶函数

2.1 装饰器基础:从语法糖到高阶函数

装饰器是 Python 中最强大且优雅的特性之一,它允许开发者在不修改原函数代码的前提下,为其添加新功能。理解装饰器的关键在于掌握两个核心概念:高阶函数语法糖。本节将深入剖析这两个概念,揭示装饰器的工作机制。

高阶函数:装饰器的基石

在 Python 中,函数是一等公民(First-class Citizen)。这意味着函数可以像其他数据类型(如整数、字符串)一样被传递、赋值和作为返回值。高阶函数(Higher-order Function)是指能够接受其他函数作为参数,或者将函数作为返回值的函数。这正是装饰器能力的源泉。

让我们通过一个简单的例子来理解高阶函数:

def greet(name):return f"Hello, {name}!"def shout(func):"""一个高阶函数,它接受一个函数并返回一个新函数"""def wrapper(name):# 在调用原函数的基础上添加新行为:将结果转为大写original_result = func(name)new_result = original_result.upper() + "!!!"return new_resultreturn wrapper# 使用高阶函数:将 greet 函数传递给 shout
enhanced_greet = shout(greet)
print(enhanced_greet("Alice"))  # 输出:HELLO, ALICE!!!!

在这个例子中,shout 是一个高阶函数:

  • 它接受一个函数 func 作为参数。
  • 它内部定义了一个新函数 wrapper
  • 它最终返回这个新函数 wrapper

当我们调用 enhanced_greet = shout(greet) 时,实际上创建了一个增强版greet 函数。这个新函数在保留原 greet 功能的同时,还添加了将结果转为大写并添加感叹号的行为。

比喻理解:想象一个咖啡店。你点了一杯普通咖啡(原函数 greet)。咖啡师(高阶函数 shout)可以在这杯咖啡的基础上添加糖、牛奶或肉桂粉(新功能),然后给你一杯调制好的特色咖啡(增强版函数 enhanced_greet),而不需要改变咖啡本身的制作方法。

装饰器语法糖:优雅的简写

虽然上面的高阶函数用法完全有效,但 Python 提供了一种更加优雅的写法——装饰器语法糖(Decorator Syntax Sugar),使用 @ 符号。

让我们用装饰器语法重写上面的例子:

def shout(func):def wrapper(name):original_result = func(name)new_result = original_result.upper() + "!!!"return new_resultreturn wrapper@shout
def greet(name):return f"Hello, {name}!"# 现在直接调用 greet 就已经是增强版的了
print(greet("Alice"))  # 输出:HELLO, ALICE!!!!

@shout 这行代码实际上等价于我们之前写的 greet = shout(greet)。这种语法更加直观和简洁,将装饰逻辑与函数定义放在一起,提高了代码的可读性。

深入理解装饰器执行流程

为了更清晰地理解装饰器的工作机制,让我们添加一些打印语句来跟踪执行流程:

def my_decorator(func):print("步骤1:装饰器函数被调用,接收原函数")def wrapper():print("步骤3:wrapper 函数在执行原函数前添加新功能")result = func()  # 调用原函数print("步骤4:wrapper 函数在执行原函数后添加新功能")return resultprint("步骤2:装饰器返回 wrapper 函数")return wrapper@my_decorator
def say_hello():print("步骤5:原函数执行核心逻辑")return "Hello World!"print("准备调用被装饰的函数...")
print(say_hello())

运行这段代码,你会看到如下输出:

步骤1:装饰器函数被调用,接收原函数
步骤2:装饰器返回 wrapper 函数
准备调用被装饰的函数...
步骤3:wrapper 函数在执行原函数前添加新功能
步骤5:原函数执行核心逻辑
步骤4:wrapper 函数在执行原函数后添加新功能
Hello World!

这个执行流程揭示了几个关键点:

  1. 装饰时机:装饰器在函数定义时立即执行,而不是在函数调用时。
  2. 函数替换:原函数 say_hello 被替换成了 wrapper 函数。
  3. 调用链:当我们调用 say_hello() 时,实际上是在调用 wrapper()
处理带参数的函数

在实际应用中,我们经常需要装饰带参数的函数。这需要我们在 wrapper 函数中使用 *args**kwargs 来接收任意数量的参数:

def universal_decorator(func):def wrapper(*args, **kwargs):print(f"即将调用函数: {func.__name__}")print(f"参数: args={args}, kwargs={kwargs}")# 将参数原样传递给原函数result = func(*args, **kwargs)print(f"函数返回: {result}")return resultreturn wrapper@universal_decorator
def add(a, b):return a + b@universal_decorator
def greet(name, greeting="Hello"):return f"{greeting}, {name}!"print(add(3, 5))
print(greet("Bob", greeting="Hi"))

这种通用的参数处理方式使得装饰器可以应用于几乎任何函数,无论其参数签名如何。

保留原函数的元信息

当使用装饰器时,原函数会被 wrapper 函数替换,这会导致原函数的一些元信息(如函数名、文档字符串等)丢失:

@shout
def greet(name):"""一个简单的问候函数"""return f"Hello, {name}!"print(greet.__name__)  # 输出:wrapper
print(greet.__doc__)   # 输出:None

为了解决这个问题,Python 提供了 functools.wraps 装饰器,它能够将原函数的元信息复制到包装函数中:

import functoolsdef shout(func):@functools.wraps(func)  # 保留原函数的元信息def wrapper(*args, **kwargs):original_result = func(*args, **kwargs)new_result = original_result.upper() + "!!!"return new_resultreturn wrapper@shout
def greet(name):"""一个简单的问候函数"""return f"Hello, {name}!"print(greet.__name__)  # 输出:greet
print(greet.__doc__)   # 输出:一个简单的问候函数

最佳实践:在定义装饰器时,总是使用 @functools.wraps(func) 来装饰内部的 wrapper 函数,这是一个被广泛遵循的约定。

装饰器的实际应用场景

装饰器在实际开发中有着广泛的应用:

  1. 日志记录:自动记录函数的调用信息和执行时间
  2. 权限验证:在函数执行前检查用户权限
  3. 性能监控:测量函数执行时间
  4. 缓存:存储函数计算结果,避免重复计算
  5. 输入验证:自动验证函数参数的合法性
import time
import functoolsdef timer(func):"""测量函数执行时间的装饰器"""@functools.wraps(func)def wrapper(*args, **kwargs):start_time = time.perf_counter()result = func(*args, **kwargs)end_time = time.perf_counter()print(f"函数 {func.__name__} 执行耗时: {end_time - start_time:.4f} 秒")return resultreturn wrapper@timer
def expensive_operation():"""模拟一个耗时操作"""time.sleep(1)return "操作完成"print(expensive_operation())

通过这个基础章节的学习,我们已经建立了装饰器的核心概念:装饰器本质上是高阶函数的语法糖,它通过接收一个函数、包装它、然后返回包装后的函数来工作。这种模式为后续学习更复杂的装饰器用法(如带参数的装饰器、类装饰器等)奠定了坚实的基础。

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

相关文章:

  • 什么是网站维护中珠宝 网站欣赏
  • 《投资-162》谨慎参与大涨之后的大跌的反弹。
  • 【区块链】一、原理与起源
  • LeetCode算法日记 - Day 94: 最长的斐波那契子序列的长度
  • 站长之家特效网站成都记者留言网站
  • 从咨询师到产品创造者:当AI让‘重复劳动‘变成创业金矿
  • 浅学Java-设计模式
  • Java Vector集合全面解析:线程安全的动态数组
  • FIB为什么要用液态镓来做离子源?
  • zabbix深度监控之邮件告警、微信群和微信告警
  • h5手机网站建设网页制作开版费
  • 企业做网站需要多少钱江西省住房建设厅统计网站
  • 游戏登录接口被爆破?从限流到 AI 防护的完整防御方案
  • 【训练技巧】优化器adam和adamw的公式推导详解及区别
  • 网易云网站开发网页开发的基本过程
  • 网站建设实训报告作业惠民网站建设
  • 上海华亮建设集团网站河南省城乡与住房建设厅网站首页
  • 【计算机视觉目标检测算法对比:R-CNN、YOLO与SSD全面解析】
  • 如何判断一个需求是“必须做”还是“可以等”?
  • 网站的主机做网站有发展吗
  • 力扣.84柱状图中最大矩形 力扣.134加油站牛客.abb(hard 动态规划+哈希表)牛客.哈夫曼编码
  • Verilog宏define
  • 性能瓶颈如何识别定位
  • ubuntu24.04制作离线本地APT源
  • UDS诊断服务基础详解之十四—85服务
  • 神经符号模型与增量学习——下一代可控人工智能的正统新范式
  • 企业官方网站开发如何入账做交通分析的网站
  • 如何使用爱站网婚庆网站建设公司
  • 高职大数据技术专业学习与发展指南
  • 上海网站建设的网站crm客户关系管理论文