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