一、decorator库概述
decorator是Python中专门用于简化装饰器编写的第三方库,核心作用是帮助开发者快速创建标准、规范的装饰器,自动保留被装饰函数的元信息(如函数名、文档字符串、参数签名),解决原生装饰器容易丢失函数元数据的问题。其原理是通过封装包装逻辑,自动完成functools.wraps的底层操作,降低装饰器编写门槛。该库轻量无侵入,使用简单,适合所有Python版本,License为BSD许可。优点是编写简洁、兼容性强、自动保留函数信息,缺点是仅专注装饰器场景,功能单一。

二、decorator库安装方法
decorator作为PyPI上的标准第三方库,可通过pip命令快速安装,兼容Python 2.7至Python 3.12+所有主流版本,安装命令如下:
pip install decorator
安装完成后,可在Python交互环境中执行导入命令验证是否安装成功:
import decorator
print(decorator.__version__)
若正常输出版本号,说明安装无误,可直接在项目中使用。
三、decorator库基础使用详解
3.1 原生装饰器的痛点
在不使用decorator库时,Python原生装饰器需要手动使用functools.wraps修饰包装函数,否则被装饰后的函数会丢失原有的__name__、__doc__、参数签名等信息,导致调试、文档生成、反射操作出现异常。
原生装饰器示例:
import functools
def my_decorator(func):
def wrapper(*args, **kwargs):
print("执行函数前")
result = func(*args, **kwargs)
print("执行函数后")
return result
return wrapper
@my_decorator
def add(a, b):
"""两数相加函数"""
return a + b
print(add.__name__) # 输出 wrapper,而非 add
print(add.__doc__) # 输出 None,丢失文档字符串
可以看到,被装饰后的函数add的名称和文档字符串都被替换成了包装函数wrapper的信息,这在实际开发中会带来诸多不便。
3.2 使用decorator编写基础装饰器
decorator库提供了decorator装饰器,只需将包装函数作为参数传入,即可自动保留被装饰函数的所有元信息,无需手动处理functools.wraps。
基础使用示例:
from decorator import decorator
@decorator
def my_decorator(func, *args, **kwargs):
print("函数执行前操作")
result = func(*args, **kwargs)
print("函数执行后操作")
return result
@my_decorator
def add(a, b):
"""两数相加函数"""
return a + b
# 调用函数
print(add(2, 3))
# 查看函数元信息
print(add.__name__) # 输出 add,保留原函数名
print(add.__doc__) # 输出 两数相加函数,保留文档字符串
代码说明:
- 导入
decorator库中的核心装饰器函数; - 用
@decorator修饰自定义装饰器函数,函数参数固定为func, *args, **kwargs; func代表被装饰的原函数,*args, **kwargs接收原函数的所有参数;- 直接在装饰器函数中编写前置、后置逻辑,最后返回原函数的执行结果;
- 被装饰后的函数完整保留原有的名称、文档字符串、参数签名。
执行结果:
函数执行前操作
函数执行后操作
5
add
两数相加函数
3.3 带参数的装饰器实现
decorator库支持编写带参数的装饰器,只需在基础装饰器外层再包裹一层函数,用于接收自定义参数,使用方式更加灵活。
带参数装饰器示例:
from decorator import decorator
def log(level="info"):
@decorator
def log_decorator(func, *args, **kwargs):
print(f"[{level.upper()}] 执行函数: {func.__name__}")
result = func(*args, **kwargs)
print(f"[{level.upper()}] 函数执行完成")
return result
return log_decorator
# 使用默认参数
@log()
def multiply(a, b):
"""两数相乘函数"""
return a * b
# 使用自定义参数
@log(level="error")
def divide(a, b):
"""两数相除函数"""
return a / b
# 调用函数
print(multiply(4, 5))
print(divide(10, 2))
代码说明:
- 定义外层函数
log,接收装饰器参数level,默认值为info; - 内层使用
@decorator修饰实际的装饰器逻辑; - 外层函数返回内层装饰器,实现参数传递;
- 调用装饰器时可传入自定义参数,控制装饰器的行为。
执行结果:
[INFO] 执行函数: multiply
[INFO] 函数执行完成
20
[ERROR] 执行函数: divide
[ERROR] 函数执行完成
5.0
3.4 装饰类方法
decorator库不仅支持装饰普通函数,还能完美兼容类的实例方法、类方法、静态方法,无需额外修改代码,适配面向对象开发场景。
装饰类方法示例:
from decorator import decorator
@decorator
def time_record(func, *args, **kwargs):
import time
start = time.time()
result = func(*args, **kwargs)
end = time.time()
print(f"函数 {func.__name__} 执行耗时: {end - start:.4f}s")
return result
class Calculator:
"""计算器类"""
@time_record
def add(self, a, b):
return a + b
@classmethod
@time_record
def multiply(cls, a, b):
return a * b
@staticmethod
@time_record
def subtract(a, b):
return a - b
# 创建实例并调用
calc = Calculator()
print(calc.add(10, 20))
print(Calculator.multiply(5, 6))
print(Calculator.subtract(30, 10))
代码说明:
- 定义通用的耗时统计装饰器
time_record; - 分别装饰实例方法、类方法、静态方法;
- 装饰器无需区分方法类型,自动适配所有类方法场景;
- 执行后可正常输出函数耗时,且保留类方法的元信息。
四、decorator库高级用法
4.1 保留函数参数签名
在原生装饰器中,即使使用functools.wraps,也可能无法完整保留函数的参数签名,而decorator库可以完美解决这个问题,让inspect模块能正确获取函数参数信息。
参数签名保留示例:
from decorator import decorator
import inspect
@decorator
def simple_decorator(func, *args, **kwargs):
return func(*args, **kwargs)
@simple_decorator
def user_info(name: str, age: int, gender: str = "male") -> str:
"""获取用户信息"""
return f"姓名:{name}, 年龄:{age}, 性别:{gender}"
# 获取函数签名
sig = inspect.signature(user_info)
print("函数参数签名:", sig)
# 获取函数注解
print("函数参数注解:", user_info.__annotations__)
代码说明:
- 使用
inspect.signature获取被装饰函数的参数签名; - decorator库完整保留了参数名称、默认值、类型注解;
- 原生装饰器无法实现这种完整的参数签名保留效果。
执行结果:
函数参数签名: (name: str, age: int, gender: str = 'male') -> str
函数参数注解: {'name': <class 'str'>, 'age': <class 'int'>, 'gender': <class 'str'>, 'return': <class 'str'>}
4.2 叠加多个装饰器
decorator库支持多个装饰器叠加使用,执行顺序与原生装饰器一致,且所有装饰器都能正常保留函数元信息,无冲突问题。
多装饰器叠加示例:
from decorator import decorator
@decorator
def decorator1(func, *args, **kwargs):
print("装饰器1前置")
res = func(*args, **kwargs)
print("装饰器1后置")
return res
@decorator
def decorator2(func, *args, **kwargs):
print("装饰器2前置")
res = func(*args, **kwargs)
print("装饰器2后置")
return res
@decorator1
@decorator2
def test_func():
print("执行原函数")
test_func()
print("函数名:", test_func.__name__)
执行结果:
装饰器1前置
装饰器2前置
执行原函数
装饰器2后置
装饰器1后置
函数名: test_func
4.3 无侵入式装饰现有函数
除了使用@语法糖装饰函数外,decorator库还支持无侵入式地为现有函数添加装饰器,无需修改原函数定义,适合对已有项目进行扩展。
无侵入式装饰示例:
from decorator import decorator
@decorator
def log_decorator(func, *args, **kwargs):
print(f"调用函数: {func.__name__}")
return func(*args, **kwargs)
# 定义原始函数
def hello(name):
return f"Hello, {name}"
# 无侵入式添加装饰器
hello = log_decorator(hello)
# 调用装饰后的函数
print(hello("Python"))
执行结果:
调用函数: hello
Hello, Python
五、实际开发案例
5.1 接口请求重试装饰器
在网络请求、接口调用场景中,经常需要实现失败重试功能,使用decorator库可以快速编写通用的重试装饰器,适配所有请求函数。
from decorator import decorator
import time
import requests
def retry(max_retry=3, delay=1):
@decorator
def retry_decorator(func, *args, **kwargs):
for i in range(max_retry):
try:
return func(*args, **kwargs)
except Exception as e:
print(f"第{i+1}次执行失败,错误信息: {e},{delay}秒后重试")
time.sleep(delay)
raise Exception(f"重试{max_retry}次后仍执行失败")
return retry_decorator
# 使用重试装饰器装饰请求函数
@retry(max_retry=2, delay=0.5)
def get_api_data(url):
"""请求接口数据"""
response = requests.get(url, timeout=3)
response.raise_for_status()
return response.json()
# 调用函数
try:
data = get_api_data("https://api.github.com")
print("请求成功:", data)
except Exception as e:
print("最终请求失败:", e)
5.2 权限校验装饰器
在Web开发、接口服务中,权限校验是常用功能,使用decorator库编写权限校验装饰器,可快速实现接口权限控制。
from decorator import decorator
user_permissions = ["read", "write"]
def require_permission(permission):
@decorator
def permission_decorator(func, *args, **kwargs):
if permission not in user_permissions:
raise PermissionError(f"缺少{permission}权限,无法执行操作")
print(f"权限{permission}校验通过")
return func(*args, **kwargs)
return permission_decorator
@require_permission("write")
def create_data(data):
"""创建数据"""
return f"创建数据成功: {data}"
@require_permission("delete")
def delete_data(data_id):
"""删除数据"""
return f"删除数据{data_id}成功"
# 调用有权限的函数
print(create_data({"id": 1, "name": "test"}))
# 调用无权限的函数
try:
delete_data(1)
except PermissionError as e:
print(e)
相关资源
- Pypi地址:https://pypi.org/project/decorator/
- Github地址:https://github.com/micheles/decorator
- 官方文档地址:https://decorator.readthedocs.io/
关注我,每天分享一个实用的Python自动化工具。
