Python 装饰器 decorator

1. 什么是装饰器

装饰器(Decorator)是 Python 中一种非常优雅的语法糖,它允许你在不修改原函数代码的前提下,为函数动态增加额外的功能。简单来说,装饰器就是一个接收函数作为参数、并返回一个新函数的高阶函数。

装饰器最常见的应用场景包括:日志记录、性能计时、权限校验、缓存结果等。它让代码更加简洁、可复用,是 Python 进阶路上必须掌握的核心技能之一。

2. 函数是一等公民

在理解装饰器之前,需要先明确一个 Python 的重要特性:函数是一等公民。这意味着函数可以像普通变量一样被赋值、作为参数传递、作为返回值返回。

python 复制代码
def greet(name):
    return f"Hello, {name}!"

# 函数可以赋值给变量
say_hello = greet
print(say_hello("Alice"))  # 输出: Hello, Alice!

# 函数可以作为参数传递
def call_func(func, arg):
    return func(arg)

print(call_func(greet, "Bob"))  # 输出: Hello, Bob!

正是因为函数可以像普通对象一样被传递和返回,装饰器才有了实现的基础。

3. 自己写装饰器 使用 @ 语法糖

上面的例子中,say_hello 没有参数。如果被装饰的函数需要接收参数,wrapper 必须使用 *args**kwargs 来接收任意数量的位置参数和关键字参数:

python 复制代码
def log_decorator(func):
    def wrapper(*args, **kwargs):
        print(f"调用函数: {func.__name__}, 参数: {args}, {kwargs}")
        result = func(*args, **kwargs)
        print(f"函数返回: {result}")
        return result
    return wrapper

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

print(add(3, 5))

运行结果:

复制代码
调用函数: add, 参数: (3, 5), {}
函数返回: 8
8

使用 *args**kwargs 后,装饰器可以适用于任意签名的函数,通用性大大增强。

4. 带参数的装饰器

有时我们希望装饰器本身也能接收参数,比如指定日志级别。这时需要在装饰器外层再包一层函数:

python 复制代码
def repeat(times):
    def decorator(func):
        def wrapper(*args, **kwargs):
            for _ in range(times):
                result = func(*args, **kwargs)
            return result
        return wrapper
    return decorator

@repeat(3)
def greet(name):
    print(f"Hello, {name}!")

greet("Alice")

运行结果:

复制代码
Hello, Alice!
Hello, Alice!
Hello, Alice!

这里 repeat(3) 先执行,返回真正的装饰器 decorator,再由 decorator 装饰 greet 函数。三层嵌套结构是带参数装饰器的标准写法。

5. langchain 中的 tool 装饰器

定义

python 复制代码
import inspect
from dataclasses import dataclass
from typing import Callable


@dataclass
class Tool:
    name: str
    description: str
    func: Callable
    args_schema: dict

    def invoke(self, *args, **kwargs):
        return self.func(*args, **kwargs)

    def __call__(self, *args, **kwargs):
        return self.invoke(*args, **kwargs)


def tool(func: Callable) -> Tool:
    """把普通函数包装成 Tool 对象"""
    sig = inspect.signature(func)
    args_schema = {
        name: param.annotation.__name__ if param.annotation != inspect.Parameter.empty else "Any"
        for name, param in sig.parameters.items()
    }

    return Tool(
        name=func.__name__,
        description=(func.__doc__ or "").strip(),
        func=func,
        args_schema=args_schema,
    )

用例

python 复制代码
@tool
def add(a: int, b: int) -> int:
    """Add two numbers."""
    return a + b


print(add.name)          # add
print(add.description)   # Add two numbers.
print(add.args_schema)   # {'a': 'int', 'b': 'int'}
print(add.invoke(1, 2))  # 3

6. 总结

装饰器是 Python 中非常强大的特性,核心要点可以归纳为:

  • 本质:装饰器是一个接收函数、返回新函数的高阶函数。
  • 语法糖@decorator 等价于 func = decorator(func)
  • 通用性 :使用 *args**kwargs 让装饰器适配任意函数签名。
  • 元信息 :使用 functools.wraps 保留原函数的名称和文档。
  • 执行顺序:多个装饰器从下往上应用,从上往下调用。
  • 实现方式:既可以用函数实现,也可以用类实现。

掌握装饰器后,你可以写出更加简洁、优雅且可复用的 Python 代码。建议在实际项目中多尝试用装饰器抽取公共逻辑,体会它带来的便利。

相关推荐
用户83562907805112 小时前
Python 实现 Word 文档域的插入与管理
后端·python
quantdash_cc12 小时前
从数据采集到策略消费,股票日内行情管道应该怎么设计?
开发语言·python·数据分析·量化交易·股票数据·quantdash
郝学胜-神的一滴12 小时前
C++20模板元编程 01:从零吃透模板核心底层逻辑
开发语言·c++·vscode·程序人生·开源
程序员杰哥12 小时前
UI自动化测试:Jenkins配置
自动化测试·软件测试·python·测试工具·职场和发展·jenkins·测试用例
hhzz13 小时前
【OpenCV 入门到精通 07】滤波、阈值与形态学:图像去噪与形状处理
人工智能·python·opencv·计算机视觉
可乐鸡翅yeah_13 小时前
HLS流媒体首屏起播慢深度优化,从分片、索引、播放器全链路调优
开发语言·javascript·ecmascript·m3u8·m3u8在线
luj_176813 小时前
生物体如何应对功能击穿?
c语言·开发语言·c++·经验分享·算法
luj_176813 小时前
击穿分析五大关键步骤
开发语言·网络·c++·经验分享·算法
wuyk55513 小时前
从零吃透 MQTT 通信|第 11 章 MQTT 项目调试验证、性能优化、常见疑难问题、OTA 升级基础
c语言·开发语言·stm32·学习·性能优化
步行cgn13 小时前
Spring 注入 Properties 详解
java·python·spring