装饰器是 Python 中用于修改函数 / 类行为的高阶函数,核心是通过包装目标对象,在不修改其源码的前提下增加额外功能(如日志、计时、权限校验等)。装饰器遵循 “开放封闭原则”,是 Python 进阶的核心特性之一。

一、装饰器核心原理

装饰器本质是:

  1. 定义一个接收函数 / 类作为参数的外层函数;
  2. 内层函数包装原函数的执行逻辑(前置 / 后置操作);
  3. 返回内层函数(替换原函数)。

核心语法:@装饰器名 是语法糖,等价于 原函数 = 装饰器名(原函数)

二、装饰器分类与代码示例

1. 基础无参装饰器(最常用)

场景:给函数增加简单的额外功能(如日志、计时)。

示例 1:计时装饰器(统计函数执行时间)
import time

# 定义装饰器
def timer_decorator(func):
    # 内层包装函数(*args, **kwargs 兼容任意参数)
    def wrapper(*args, **kwargs):
        start = time.time()  # 前置操作:记录开始时间
        result = func(*args, **kwargs)  # 执行原函数
        end = time.time()  # 后置操作:记录结束时间
        print(f"函数 {func.__name__} 执行耗时:{end - start:.4f} 秒")
        return result  # 必须返回原函数结果,避免丢失
    return wrapper

# 使用装饰器
@timer_decorator
def calculate_sum(n):
    """计算1到n的和"""
    return sum(range(1, n+1))

# 调用测试
calculate_sum(1000000)  # 输出:函数 calculate_sum 执行耗时:0.0200 秒(示例值)
示例 2:日志装饰器(记录函数调用信息)
def log_decorator(func):
    def wrapper(*args, **kwargs):
        # 前置操作:打印调用信息
        print(f"[LOG] 函数 {func.__name__} 被调用,参数:args={args}, kwargs={kwargs}")
        result = func(*args, **kwargs)
        # 后置操作:打印返回值
        print(f"[LOG] 函数 {func.__name__} 返回值:{result}")
        return result
    return wrapper

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

add(2, 3)
# 输出:
# [LOG] 函数 add 被调用,参数:args=(2, 3), kwargs={}
# [LOG] 函数 add 返回值:5

2. 带参数的装饰器

场景:装饰器需要自定义参数(如日志级别、超时时间)。原理:在基础装饰器外层再套一层函数,用于接收装饰器参数。

示例:带级别控制的日志装饰器
def log_decorator_with_level(level="INFO"):
    # 外层:接收装饰器参数
    def decorator(func):
        # 中层:接收被装饰函数
        def wrapper(*args, **kwargs):
            # 内层:包装逻辑
            print(f"[{level}] 函数 {func.__name__} 调用,参数:{args}")
            result = func(*args, **kwargs)
            return result
        return wrapper
    return decorator

# 使用装饰器(指定级别)
@log_decorator_with_level(level="DEBUG")
def multiply(a, b):
    return a * b

# 不指定级别(使用默认值)
@log_decorator_with_level()
def subtract(a, b):
    return a - b

multiply(4, 5)  # 输出:[DEBUG] 函数 multiply 调用,参数:(4, 5)
subtract(10, 3) # 输出:[INFO] 函数 subtract 调用,参数:(10, 3)

3. 装饰类 / 类方法

示例 1:装饰类(给类增加属性 / 方法)
def add_prefix_decorator(prefix):
    def decorator(cls):
        # 给类的所有方法名加前缀
        for attr in dir(cls):
            if callable(getattr(cls, attr)) and not attr.startswith("__"):
                original_method = getattr(cls, attr)
                setattr(cls, f"{prefix}_{attr}", original_method)
        return cls
    return decorator

# 装饰类
@add_prefix_decorator("my")
class Calculator:
    def add(self, a, b):
        return a + b

# 使用
calc = Calculator()
print(calc.my_add(1, 2))  # 输出:3(调用装饰后新增的方法)
示例 2:装饰类方法 / 静态方法
def check_permission(func):
    def wrapper(self, *args, **kwargs):
        if self.user != "admin":
            raise PermissionError("无权限")
        return func(self, *args, **kwargs)
    return wrapper

class AdminSystem:
    def __init__(self, user):
        self.user = user

    @check_permission  # 装饰实例方法
    def delete_data(self):
        print("数据删除成功")

    @staticmethod
    @log_decorator  # 装饰静态方法(注意顺序:装饰器靠近方法)
    def static_func():
        print("静态方法执行")

# 测试
admin = AdminSystem("admin")
admin.delete_data()  # 输出:数据删除成功

guest = AdminSystem("guest")
guest.delete_data()  # 抛出 PermissionError

4. 保留原函数元信息(functools.wraps)

默认装饰器会丢失原函数的 __name____doc__ 等元信息,需用 functools.wraps 修复。

import functools

def decorator(func):
    @functools.wraps(func)  # 保留原函数元信息
    def wrapper(*args, **kwargs):
        return func(*args, **kwargs)
    return wrapper

@decorator
def my_func():
    """这是原函数的文档字符串"""
    pass

print(my_func.__name__)  # 输出:my_func(未用wraps则输出wrapper)
print(my_func.__doc__)   # 输出:这是原函数的文档字符串

5. 多个装饰器叠加

多个装饰器按自下而上的顺序执行(靠近函数的先执行)。

def decorator1(func):
    def wrapper(*args, **kwargs):
        print("装饰器1 前置")
        result = func(*args, **kwargs)
        print("装饰器1 后置")
        return result
    return wrapper

def decorator2(func):
    def wrapper(*args, **kwargs):
        print("装饰器2 前置")
        result = func(*args, **kwargs)
        print("装饰器2 后置")
        return result
    return wrapper

@decorator1
@decorator2
def test():
    print("原函数执行")

test()
# 输出顺序:
# 装饰器1 前置
# 装饰器2 前置
# 原函数执行
# 装饰器2 后置
# 装饰器1 后置

三、装饰器常见应用场景

  1. 性能监控:统计函数执行时间、调用次数;
  2. 日志记录:记录函数调用参数、返回值、异常;
  3. 权限校验:接口 / 方法的访问权限控制;
  4. 缓存优化:缓存函数返回结果(如 lru_cache);
  5. 参数校验:检查函数入参类型 / 范围;
  6. 重试机制:函数执行失败时自动重试。

四、内置装饰器

Python 提供了常用内置装饰器:

  • @property:将方法转为属性;
  • @staticmethod:定义静态方法;
  • @classmethod:定义类方法;
  • @functools.lru_cache:缓存函数结果(优化重复计算)。
import functools

@functools.lru_cache(maxsize=None)  # 无限制缓存
def fib(n):
    if n <= 1:
        return n
    return fib(n-1) + fib(n-2)

print(fib(100))  # 缓存后执行极快

总结

装饰器的核心是高阶函数 + 闭包,关键要点:

  1. *args, **kwargs 保证装饰器兼容任意参数;
  2. functools.wraps 保留原函数元信息;
  3. 带参装饰器需嵌套三层函数;
  4. 多个装饰器叠加时注意执行顺序;
  5. 可装饰函数、类、类方法等任意可调用对象。

装饰器是 Python 中 “优雅扩展功能” 的最佳实践,熟练掌握可大幅提升代码的简洁性和可维护性。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐