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

Python 装饰器(Decorators)

  1. 什么是装饰器?
    装饰器(Decorator)本质上是一个 修改其他函数功能的函数。它的核心思想是:不修改原函数代码,动态添加新功能。比如:

记录函数执行时间

检查用户权限

缓存计算结果

自动重试失败操作

  1. 理解函数是“对象”
    在 Python 中,函数也是对象,可以像变量一样传递。这是装饰器的核心基础!
示例 1:函数赋值给变量
python
复制
def say_hello():
    print("Hello!")

将函数赋值给变量

greet = say_hello  

调用变量(实际调用函数)

greet()  # 输出: Hello!
示例 2:函数作为参数传递
python
复制
def call_twice(func):
    func()  # 第一次调用
    func()  # 第二次调用

call_twice(say_hello)  
# 输出:
# Hello!
# Hello!
  1. 最简单的装饰器
    假设我们要在函数执行前后打印日志:

步骤 1:定义一个装饰器函数

python
复制
def log_decorator(func):
    def wrapper():
        print("函数开始执行...")
        func()  # 调用原函数
        print("函数执行完毕!")
    return wrapper  # 返回新函数

步骤 2:使用装饰器

python
复制
@log_decorator  # 语法糖(等价于 say_hello = log_decorator(say_hello)
def say_hello():
    print("Hello!")

say_hello()

# 输出:
# 函数开始执行...
# Hello!
# 函数执行完毕!
  1. 装饰器的执行过程
    当使用 @log_decorator 时,实际发生了以下步骤:

传递函数:log_decorator(say_hello) 被调用,参数是原函数 say_hello

返回新函数:log_decorator 返回内部定义的 wrapper 函数

替换原函数:say_hello 变量指向新的 wrapper 函数

  1. 处理带参数的函数
    如果被装饰的函数需要参数,怎么办?让 wrapper 接受参数并传递给原函数。

示例:记录函数参数

python
复制
def log_args(func):
    def wrapper(*args, **kwargs):  # 接受任意参数
        print(f"参数: args={args}, kwargs={kwargs}")
        return func(*args, **kwargs)  # 传递参数给原函数
    return wrapper

@log_args
def add(a, b):
    return a + b

print(add(3, b=5))  
# 输出:
# 参数: args=(3,), kwargs={'b': 5}

8

  1. 装饰器带参数
    如果装饰器本身需要参数(比如指定日志级别),需要再包裹一层。

示例:根据日志级别打印

python
复制
def log_level(level):  # 外层函数接受参数
    def decorator(func):  # 装饰器函数
        def wrapper(*args, **kwargs):
            print(f"[{level}] 函数开始执行...")
            result = func(*args, **kwargs)
            print(f"[{level}] 函数执行完毕!")
            return result
        return wrapper
    return decorator  # 返回装饰器

@log_level("INFO")  # 等价于 add = log_level("INFO")(add)
def add(a, b):
    return a + b

add(2, 3)
# 输出:
# [INFO] 函数开始执行...
# [INFO] 函数执行完毕!
  1. 保留原函数的信息
    使用装饰器后,原函数的名称(name)和文档(doc)会被替换为 wrapper。用 functools.wraps 解决这个问题:
python
复制
from functools import wraps

def log_decorator(func):
    @wraps(func)  # 保留原函数信息
    def wrapper(*args, **kwargs):
        print("开始执行...")
        result = func(*args, **kwargs)
        print("执行完毕!")
        return result
    return wrapper

@log_decorator
def say_hello():
    """打招呼的函数"""
    print("Hello!")

print(say_hello.__name__)  # 输出: say_hello(而不是 wrapper)
print(say_hello.__doc__)   # 输出: 打招呼的函数
  1. 类装饰器
    除了函数,还可以用类实现装饰器。通过实现 call 方法:
python
复制
class CountCalls:
    def __init__(self, func):
        self.func = func
        self.calls = 0

    def __call__(self, *args, **kwargs):
        self.calls += 1
        print(f"函数被调用了 {self.calls} 次")
        return self.func(*args, **kwargs)

@CountCalls
def say_hello():
    print("Hello!")

say_hello()  # 输出: 函数被调用了 1 次 → Hello!
say_hello()  # 输出: 函数被调用了 2 次 → Hello

!
9. 实际应用场景
装饰器在 Python 中广泛应用,例如:

Web框架:@app.route(“/”)(Flask/Django)

权限验证:@login_required

性能测试:计算函数执行时间

缓存:@lru_cache(内置装饰器)

总结
核心思想:装饰器通过“函数嵌套”和“函数作为参数”实现功能扩展。

关键点:

使用 @decorator 语法糖

处理参数:*args 和 **kwargs

保留原函数信息:@wraps(func)

类装饰器:实现 call 方法

试着写几个自己的装饰器(比如记录执行时间),就能快速掌握这个概念!

相关文章:

  • 华为虚墙配置实验
  • FLEXlm如何通过web调用
  • 银河麒麟高级服务器操作系统基础docker镜像封装http和docker端口映射操作
  • 大模型AI Agent:简介(第一部分)—— 特性、组件、运作及应用全景
  • Nature招牌1区Top认证!可解释多模态融合模型取得重大突破!
  • 座舱与智驾“双轮驱动”,芯擎科技打造智能汽车“芯”标杆
  • 香港电讯企业托管服务,助企业实现高效IT管理与运营
  • MySQL8.4 InnoDB Cluster高可用集群使用指南
  • 嵌入式c学习第十天
  • 留记录excel 模板导入
  • 深度学习处理时间序列(3)
  • AOA与TOA混合定位,MATLAB例程,三维空间下的运动轨迹,滤波使用EKF,附下载链接
  • Promise详解
  • 食品级低聚木糖市场报告​:2024年全球食品级低聚木糖市场销售额达到了0.35亿美元
  • Spring Cloud ReactorServiceInstanceLoadBalancer 自定义负载均衡
  • Codeforces Round 1013 (Div. 3)-F
  • 信息系统项目管理师知识体系
  • 0328-内存图2
  • 并发编程--共享内存SHM
  • OpenGL —— 基于Qt的视频播放器 - ffmpeg硬解码,QOpenGL渲染yuv420p或nv12视频(附源码)
  • 周国辉谈花开岭现象 :年轻的公益人正在用行动点亮希望
  • 泽连斯基与美国副总统及国务卿会谈,讨论伊斯坦布尔谈判等问题
  • 倒票“黄牛”屡禁不绝怎么破?业内:强化文旅市场票务公开制度
  • 光明日报社副总编辑薄洁萍调任求是杂志社副总编辑
  • 广西:坚决拥护党中央对蓝天立进行审查调查的决定
  • 消息人士称俄方反对美国代表参加俄乌直接会谈