Python3 中的装饰器(Decorator)是一种非常重要的语法特性,本质上是对函数或类进行“包装”的一种机制。它允许你在不修改原函数代码的情况下,动态地给函数增加功能

装饰器在 Web框架、日志系统、权限控制、缓存、性能统计 等场景中非常常见。


一、装饰器的本质

一句话理解: 原函数f,装饰器g,那么就有g(f(X))

二、最简单的装饰器示例

示例:函数执行前后打印日志

def decorator(func):
    def wrapper():
        print("函数执行前")
        func()
        print("函数执行后")
    return wrapper


@decorator
def say_hello():
    print("Hello")


say_hello()

输出:

函数执行前
Hello
函数执行后

执行流程:

say_hello = decorator(say_hello)

调用 say_hello()
实际上调用 wrapper()

结构图:

say_hello()
   ↓
wrapper()
   ↓
func()  (原函数)

三、带参数函数的装饰器

现实中函数一般都有参数。

示例

def decorator(func):
    def wrapper(*args, **kwargs):
        print("执行前")
        result = func(*args, **kwargs)
        print("执行后")
        return result
    return wrapper


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


print(add(3, 5))

输出:

执行前
执行后
8

关键点:

*args
**kwargs

保证装饰器可以适用于任何函数。


四、使用 functools.wraps(重要)

装饰器会覆盖原函数信息

print(add.__name__)

会输出:

wrapper

解决方法:

from functools import wraps

def decorator(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        print("执行前")
        return func(*args, **kwargs)
    return wrapper

作用:

保持

__name__
__doc__
__module__

等元信息。


五、带参数的装饰器(高级)

有时候装饰器本身也需要参数。

例如:

@retry(3)
@cache(10)
@timeout(5)

实现结构:

三层函数

示例:

def repeat(n):
    def decorator(func):
        def wrapper(*args, **kwargs):
            for i in range(n):
                func(*args, **kwargs)
        return wrapper
    return decorator


@repeat(3)
def hello():
    print("hello")


hello()

输出:

hello
hello
hello

等价于:

hello = repeat(3)(hello)

结构:

repeat(n)
   ↓
decorator(func)
   ↓
wrapper()

六、类装饰器

装饰器不仅可以装饰函数,还可以装饰类。

示例:

def add_attr(cls):
    cls.author = "Tom"
    return cls


@add_attr
class Book:
    pass


print(Book.author)

输出:

Tom

七、多个装饰器

@A
@B
@C
def f():
    pass

执行顺序:

f = A(B(C(f)))

调用顺序:

A wrapper
   ↓
B wrapper
   ↓
C wrapper
   ↓
f

八、装饰器的常见应用场景

1 日志记录

def log(func):
    def wrapper(*args, **kwargs):
        print(f"调用函数 {func.__name__}")
        return func(*args, **kwargs)
    return wrapper

常见于:

  • Web服务
  • API调用

2 性能统计

import time

def timer(func):
    def wrapper(*args, **kwargs):
        start = time.time()
        result = func(*args, **kwargs)
        print("耗时:", time.time() - start)
        return result
    return wrapper

常见:

算法测试
性能分析

3 权限控制

例如 Web API:

def login_required(func):
    def wrapper(user):
        if not user.logged_in:
            raise Exception("请登录")
        return func(user)
    return wrapper

Flask / FastAPI 中非常常见。


4 缓存(非常经典)

Python 自带:

functools.lru_cache

示例:

from functools import lru_cache

@lru_cache(maxsize=128)
def fib(n):
    if n < 2:
        return n
    return fib(n-1) + fib(n-2)

作用:

动态规划
缓存计算结果

5 重试机制

例如网络请求:

def retry(n):
    def decorator(func):
        def wrapper(*args, **kwargs):
            for _ in range(n):
                try:
                    return func(*args, **kwargs)
                except:
                    pass
            raise Exception("失败")
        return wrapper
    return decorator

6 Web框架(最常见)

例如 Flask

@app.route("/home")
def home():
    return "hello"

@app.route 就是装饰器。

作用:

URL → 函数映射

九、装饰器在大型项目中的作用

在大型项目(如 AI / Web / 后端)中,装饰器常用于:

作用 示例
日志 log decorator
缓存 lru_cache
权限 login_required
重试 retry
计时 timer
注册机制 register decorator
路由 Flask route
配置注入 Hydra / draccus

例如你之前问的 draccus 里面也经常用装饰器实现:

配置注册
配置解析

十、装饰器执行流程(面试经典)

代码:

@decorator
def f():
    pass

执行顺序:

1 定义 f
2 执行 decorator(f)
3 返回 wrapper
4 f = wrapper
5 调用 f() 实际执行 wrapper()

十一、装饰器结构总结

最通用模板

from functools import wraps

def decorator(func):

    @wraps(func)
    def wrapper(*args, **kwargs):

        # before
        result = func(*args, **kwargs)
        # after

        return result

    return wrapper

十二、一张完整结构图

@decorator
def func()

        ↓

decorator(func)

        ↓

wrapper

        ↓

func = wrapper

        ↓

调用 func()

        ↓

wrapper()

        ↓

原函数
Logo

这里是“一人公司”的成长家园。我们提供从产品曝光、技术变现到法律财税的全栈内容,并连接云服务、办公空间等稀缺资源,助你专注创造,无忧运营。

更多推荐