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

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 方法

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


http://www.kler.cn/a/612962.html

相关文章:

  • C++方向就业
  • acwing 每日一题4888. 领导者
  • EMC知识学习三
  • firewall-cmd添加访问规则
  • Next.js 中间件鉴权绕过漏洞 (CVE-2025-29927) 复现利用与原理分析
  • 标准库中有uint32_t类型吗?
  • Pytorch学习笔记(十六)Image and Video - Transfer Learning for Computer Vision Tutorial
  • Mysql-DML
  • Linux命令大全:从入门到高效运维
  • Mac: 运行python读取CSV出现 permissionError
  • 【LeetCode 题解】数据库:180. 连续出现的数字
  • 提示词应用:IT模拟面试
  • CSS学习笔记5——渐变属性+盒子模型阶段案例
  • 构建高可用性西门子Camstar服务守护者:异常监控与自愈实践
  • k近邻算法K-Nearest Neighbors(KNN)
  • office_word中使用宏以及DeepSeek
  • 如何让DeepSeek-R1在内网稳定运行并实现随时随地远程在线调用
  • Redis原理:setnx
  • 基于深度学习的图像超分辨率技术研究与实现
  • 解决 Apache Kylin 加载 Hive 表失败的问题:深入分析与解决方案