Skip to main content
Documents
Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Back to homepage

Decorator (装饰器)

✅ 一、什么是装饰器(Decorator)

一句话:装饰器就是一个函数,用来给另外一个函数增强功能,但不修改原代码。

你写一个函数 f(),装饰器 @decorator 可以在它前后执行代码,例如增加日志、权限检查、计时功能等。

✅ 二、最简单的装饰器示例

def my_decorator(func):
    def wrapper():
        print("执行前")
        func()
        print("执行后")
    return wrapper

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

say_hello()

输出:

执行前
Hello
执行后

解释:

  • @my_decorator 等价于 say_hello = my_decorator(say_hello)
  • wrapper() 替代了原函数,但内部仍调用原函数,所以功能被“包装”了。

✅ 三、装饰器通用模板(最常用)

适用于大多数真实场景。

from functools import wraps

def decorator(fn):
    @wraps(fn)
    def wrapper(*args, **kwargs):
        print("before:", fn.__name__)
        result = fn(*args, **kwargs)
        print("after:", fn.__name__)
        return result
    return wrapper

记住:wrapper 必须接收 *args, **kwargs

这个版本能装饰任意函数。

@wraps(fn) 作用是保留原函数信息,否则 fn.__name__ 会变成 “wrapper”。

✅ 四、常见装饰器应用场景

1)打印日志

def log(fn):
    @wraps(fn)
    def wrapper(*args, **kwargs):
        print(f"[LOG] 调用函数 {fn.__name__}")
        return fn(*args, **kwargs)
    return wrapper

2)统计函数耗时

import time

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

3)检查权限(Web 后端常用)

def require_admin(fn):
    @wraps(fn)
    def wrapper(*args, **kwargs):
        if not kwargs.get("is_admin"):
            raise PermissionError("无权限")
        return fn(*args, **kwargs)
    return wrapper

4)缓存结果(常用于计算型函数)

def cache(fn):
    memo = {}

    @wraps(fn)
    def wrapper(n):
        if n not in memo:
            memo[n] = fn(n)
        return memo[n]

    return wrapper

✅ 五、装饰器带参数(★★★重点)

想要写成 @decorator(arg) 的形式?

需要 “三层函数”:

def repeat(times):
    def decorator(fn):
        @wraps(fn)
        def wrapper(*args, **kwargs):
            for _ in range(times):
                fn(*args, **kwargs)
        return wrapper
    return decorator

使用:

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

✅ 六、类装饰器(了解)

装饰器不止可以是函数,也可以是类。

class Decorator:
    def __init__(self, fn):
        self.fn = fn

    def __call__(self, *args, **kwargs):
        print("before")
        return self.fn(*args, **kwargs)

@Decorator
def hello():
    print("hello")

✅ 七、装饰器叠加(多个装饰器)

@decorator_a
@decorator_b
def f():
    pass

等价于

f = decorator_a(decorator_b(f))

下方装饰器先执行。

🎁 八、最小记忆版本(超短总结)

  • 装饰器 = 在不改原函数的前提下,额外添加功能
  • 核心公式:fn = decorator(fn)
  • 必备语法:wrapper(*args, **kwargs)
  • 最好加:from functools import wraps
  • 带参数 = 三层函数
  • 多个装饰器 = 从下往上套

最常见的 20 个装饰器实战示例

以下是 最常见、最实用、能直接复制使用的 20 个 Python 装饰器实战示例。

所有示例都经过精简,可直接用在真实项目中(包括你常用的 FastAPI 项目)。

1)日志打印装饰器(最常用)

from functools import wraps

def log(fn):
    @wraps(fn)
    def wrapper(*args, **kwargs):
        print(f"[LOG] 调用 {fn.__name__}")
        return fn(*args, **kwargs)
    return wrapper

2)函数执行计时

import time
from functools import wraps

def timer(fn):
    @wraps(fn)
    def wrapper(*args, **kwargs):
        start = time.time()
        result = fn(*args, **kwargs)
        print(f"耗时 {time.time() - start:.4f}s")
        return result
    return wrapper

3)异常捕获并打印

from functools import wraps

def catch_error(fn):
    @wraps(fn)
    def wrapper(*args, **kwargs):
        try:
            return fn(*args, **kwargs)
        except Exception as e:
            print(f"[ERROR] {fn.__name__}: {e}")
            return None
    return wrapper

4)参数类型检查(简单版)

def type_check(*types):
    def decorator(fn):
        @wraps(fn)
        def wrapper(*args):
            for a, t in zip(args, types):
                assert isinstance(a, t), f"{a} must be {t}"
            return fn(*args)
        return wrapper
    return decorator

5)简单缓存(Memoize)

def cache(fn):
    memo = {}

    @wraps(fn)
    def wrapper(*args):
        if args not in memo:
            memo[args] = fn(*args)
        return memo[args]
    return wrapper

6)限制函数执行次数

def limit_times(n):
    def decorator(fn):
        count = 0

        @wraps(fn)
        def wrapper(*args, **kwargs):
            nonlocal count
            if count >= n:
                print("已超过允许执行次数")
                return
            count += 1
            return fn(*args, **kwargs)
        return wrapper
    return decorator

7)重试机制(异常重试)

import time
from functools import wraps

def retry(times=3, delay=1):
    def decorator(fn):
        @wraps(fn)
        def wrapper(*args, **kwargs):
            for i in range(times):
                try:
                    return fn(*args, **kwargs)
                except Exception:
                    time.sleep(delay)
            raise
        return wrapper
    return decorator

8)函数结果强制为特定类型

def ensure_type(t):
    def decorator(fn):
        @wraps(fn)
        def wrapper(*args, **kwargs):
            return t(fn(*args, **kwargs))
        return wrapper
    return decorator

9)权限检查(后端必用)

def require_admin(fn):
    @wraps(fn)
    def wrapper(*args, **kwargs):
        if not kwargs.get('is_admin'):
            raise PermissionError("No permission")
        return fn(*args, **kwargs)
    return wrapper

10)打印函数入参与返回值

def trace(fn):
    @wraps(fn)
    def wrapper(*args, **kwargs):
        print(f"{fn.__name__} 入参: {args}, {kwargs}")
        result = fn(*args, **kwargs)
        print(f"{fn.__name__} 返回: {result}")
        return result
    return wrapper

11)惰性执行(用于缓存大对象的初始化)

def lazy(fn):
    cached = {}

    @wraps(fn)
    def wrapper(*args, **kwargs):
        if 'value' not in cached:
            cached['value'] = fn(*args, **kwargs)
        return cached['value']
    return wrapper

12)只执行一次(单例/初始化场景)

def once(fn):
    done = False
    result = None

    @wraps(fn)
    def wrapper(*args, **kwargs):
        nonlocal done, result
        if not done:
            result = fn(*args, **kwargs)
            done = True
        return result
    return wrapper

13)异步函数装饰器(支持 async)

import asyncio
from functools import wraps

def async_log(fn):
    @wraps(fn)
    async def wrapper(*args, **kwargs):
        print(f"【ASYNC LOG】调用 {fn.__name__}")
        return await fn(*args, **kwargs)
    return wrapper

14)函数节流(throttle)

import time

def throttle(interval):
    def decorator(fn):
        last = 0

        @wraps(fn)
        def wrapper(*args, **kwargs):
            nonlocal last
            now = time.time()
            if now - last > interval:
                last = now
                return fn(*args, **kwargs)
        return wrapper
    return decorator

15)函数防抖(debounce)

import time

def debounce(wait):
    def decorator(fn):
        last = 0

        @wraps(fn)
        def wrapper(*args, **kwargs):
            nonlocal last
            last = time.time()
            time.sleep(wait)
            if time.time() - last >= wait:
                return fn(*args, **kwargs)
        return wrapper
    return decorator

16)函数执行前后加锁(多线程)

from functools import wraps
from threading import Lock

def with_lock(lock: Lock):
    def decorator(fn):
        @wraps(fn)
        def wrapper(*args, **kwargs):
            with lock:
                return fn(*args, **kwargs)
        return wrapper
    return decorator

17)数据库事务管理(FastAPI/SQLAlchemy 常见)

def db_transaction(fn):
    @wraps(fn)
    def wrapper(db, *args, **kwargs):
        try:
            result = fn(db, *args, **kwargs)
            db.commit()
            return result
        except:
            db.rollback()
            raise
    return wrapper

18)确保函数在某个目录执行

import os
from functools import wraps

def cd(path):
    def decorator(fn):
        @wraps(fn)
        def wrapper(*args, **kwargs):
            old = os.getcwd()
            os.chdir(path)
            try:
                return fn(*args, **kwargs)
            finally:
                os.chdir(old)
        return wrapper
    return decorator

19)自动重试 + 打印重试次数

def retry_log(times=3):
    def decorator(fn):
        @wraps(fn)
        def wrapper(*args, **kwargs):
            for i in range(1, times+1):
                try:
                    return fn(*args, **kwargs)
                except Exception as e:
                    print(f"重试 {i}/{times}: {e}")
            raise
        return wrapper
    return decorator

20)将普通函数变成属性(常见于类)

def lazy_property(fn):
    attr = "_lazy_" + fn.__name__

    @property
    @wraps(fn)
    def wrapper(self):
        if not hasattr(self, attr):
            setattr(self, attr, fn(self))
        return getattr(self, attr)
    return wrapper

🎁 BONUS:送你一个装饰器万能模板(通用型)

from functools import wraps

def decorator(fn):
    @wraps(fn)
    def wrapper(*args, **kwargs):
        # 前置逻辑
        result = fn(*args, **kwargs)
        # 后置逻辑
        return result
    return wrapper