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 代码。建议在实际项目中多尝试用装饰器抽取公共逻辑,体会它带来的便利。

相关推荐
电商API_180079052471 小时前
速卖通商品采集API技术文章
java·开发语言·c++·api·跨境电商·商品详情
一晌小贪欢1 小时前
Python办公14:批量解压文件夹内的所有 ZIP/RAR 并自动分类
开发语言·python·excel·数据可视化·python办公
郑州光合科技余经理1 小时前
海外版外卖系统架构:订单怎么流转、权限怎么分
java·开发语言·前端·系统架构·uni-app·php·ai编程
Python 实战手记1 小时前
企业微信主体变更公证书办理全解析:适用场景、材料规范、踩坑点与Python信息校验脚本
开发语言·python·企业微信
longxiaozhang61 小时前
C#异常处理:程序出错了怎么办?
开发语言·数据库·c#
郝学胜_神的一滴1 小时前
Effective Python 条款 2:遵循 PEP 8 编码风格,写出高质量 Python 代码
python·算法
郝学胜-神的一滴1 小时前
Effective Python 条款 1:确认你正在使用的 Python 版本
开发语言·数据结构·python·程序人生·算法
RanMatrix1 小时前
Python列表精讲
python
路多辛2 小时前
全能型 Go Agent 框架 covonaut v1.0.8 发布:新增行内补全与多后端可观测性
开发语言·golang·agent