python3中的装饰器介绍及其应用场景

目录

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

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


一、装饰器的本质

一句话理解:

装饰器 = 接收函数 → 返回新函数 的函数。

数学表达:

复制代码
decorator(func) -> new_func

使用装饰器语法:

python 复制代码
@decorator
def foo():
    pass

等价于:

python 复制代码
foo = decorator(foo)

二、最简单的装饰器示例

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

python 复制代码
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()  (原函数)

三、带参数函数的装饰器

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

示例

python 复制代码
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(重要)

装饰器会覆盖原函数信息

python 复制代码
print(add.__name__)

会输出:

复制代码
wrapper

解决方法:

python 复制代码
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)

实现结构:

复制代码
三层函数

示例:

python 复制代码
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()

六、类装饰器

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

示例:

python 复制代码
def add_attr(cls):
    cls.author = "Tom"
    return cls


@add_attr
class Book:
    pass


print(Book.author)

输出:

复制代码
Tom

七、多个装饰器

python 复制代码
@A
@B
@C
def f():
    pass

执行顺序:

复制代码
f = A(B(C(f)))

调用顺序:

复制代码
A wrapper
   ↓
B wrapper
   ↓
C wrapper
   ↓
f

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

1 日志记录

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

常见于:

  • Web服务
  • API调用

2 性能统计

python 复制代码
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:

python 复制代码
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

示例:

python 复制代码
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 重试机制

例如网络请求:

python 复制代码
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

python 复制代码
@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 里面也经常用装饰器实现:

复制代码
配置注册
配置解析

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

代码:

python 复制代码
@decorator
def f():
    pass

执行顺序:

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

十一、装饰器结构总结

最通用模板

python 复制代码
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()

        ↓

原函数
相关推荐
sheji34162 小时前
【开题答辩全过程】以 基于Java的饮品店管理系统的实现为例,包含答辩的问题和答案
java·开发语言
大阿明2 小时前
Spring.factories
java·数据库·spring
菜鸟程序员专写BUG2 小时前
SpringBoot 事务失效报错全集|rollback不生效/事务不回滚/传播机制踩坑全解决
java·spring boot·spring
向上_503582912 小时前
配置Protobuf输出Java文件或kotlin文件
android·java·开发语言·kotlin
IAUTOMOBILE2 小时前
C++ 入门基础:开启编程新世界的大门
java·jvm·c++
秋野酱2 小时前
基于springboot的母婴商城系统设计与实现(源码+文档+部署讲解)
java·spring boot·后端
踩着两条虫2 小时前
VTJ.PRO 在线应用开发平台的后端模块系统
后端·架构·nestjs
踩着两条虫2 小时前
VTJ.PRO 在线应用开发平台的业务模块(应用、DSL、模板、订单、智能体、技能)
后端·agent·nestjs
踩着两条虫2 小时前
VTJ.PRO 在线应用开发平台的核心模块(用户、认证、RBAC、缓存、设置)
后端·低代码·nestjs