找回密码
 立即注册
搜索
热搜: 活动 交友
查看: 523|回复: 0

Pydantic | 一个用于 Python 的数据合法性验证库

[复制链接]

7

主题

8

回帖

290

积分

版主

积分
290
发表于 3-25-2025 21:07:08 | 显示全部楼层 |阅读模式
在实际项目开发中,我们经常会遇到配置数据格式混乱、数据类型不匹配的问题。例如,考虑下面这样一个 JSON 配置文件:
  1. {
  2.   "program_display_language": "zh_CN",
  3.   "log_level": "DEBUG",
  4.   "platform": "bilibili",
  5.   "room_id": "1852504554",
  6.   "danmaku_display_mode": "BOTTOM",
  7.   "sending_delay": 2,
  8.   "segment_time_length": 5,
  9.   "model_name": "turbo",
  10.   "whisper_params": {
  11.     "language": "en",
  12.     "fp16": true,
  13.     "suppress_tokens": [
  14.       -1
  15.     ],
  16.     "temperature": 0,
  17.     "beam_size": 5,
  18.     "best_of": 5
  19.   },
  20.   "translator": "ChatGPT",
  21.   "translator_params": {
  22.     "dst_language": "简体中文",
  23.     "temperature": 0
  24.   },
  25.   "max_order_num": 10,
  26.   "danmaku_text_format": "{transcription_text} {danmaku_order_num}",
  27.   "should_send_danmaku": false,
  28.   "max_retry_times": 3,
  29.   "max_chars_per_danmaku": 20,
  30.   "max_chars_per_audio_segment": 40,
  31.   "debug": false
  32. }
复制代码
在这个例子中,如果 "max_order_num" 被错误地输入了非数字字符,或者 "platform" 的值被意外设置成了 "炒饭",那么无疑会给数据合法性校验带来不少麻烦。为了避免在项目中编写冗长而复杂的检查代码,Pydantic 便应运而生——它利用 Python 的类型提示机制,提供了一种优雅而高效的数据验证方案。
什么是 Pydantic?
Pydantic 是一个基于 Python 类型提示的高性能数据解析和验证库。它通过继承自 BaseModel 的模型类,允许开发者以声明性方式定义数据结构及其类型约束。借助 Pydantic,你可以确保在数据输入阶段就捕捉到潜在的错误,从而使整个应用程序更健壮、更易维护。
例如,我们可以针对上述 JSON 配置文件定义如下的数据模型:
  1. from pydantic import BaseModel
  2. from typing import Literal

  3. class TranslatorParams(BaseModel):
  4.     model_name: str
  5.     api_key: str

  6. class Config(BaseModel):
  7.     program_display_language: Literal["zh_CN", "en"]
  8.     log_level: Literal["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"]
  9.     platform: str
  10.     room_id: int
  11.     danmaku_display_mode: Literal["FLY", "TOP", "BOTTOM"]
  12.     sending_delay: int
  13.     segment_time_length: int
  14.     model_name: Literal["tiny", "base", "small", "medium", "large", "turbo"]
  15.     whisper_params: dict
  16.     translator: Literal["ChatGPT"]
  17.     translator_params: TranslatorParams
  18.     danmaku_text_format: str
  19.     max_order_num: int
  20.     should_send_danmaku: bool
  21.     max_retry_times: int
  22.     max_chars_per_danmaku: int
  23.     max_chars_per_audio_segment: int
  24.     debug: bool

  25. class Credential(BaseModel):  # 假设 MyBaseModel 为 BaseModel 的扩展
  26.     SESSDATA: str
  27.     bili_jct: str

  28. if __name__ == '__main__':
  29.     path = "./config.json"
  30.     with open(path) as f:
  31.         json_data = f.read()
  32.         config = Config.model_validate_json(json_data)
  33.         print(config)
复制代码

上述代码中,Pydantic 根据我们定义的类型注解自动将 JSON 数据转换为相应的 Python 类型,并在数据不符合预期时抛出友好的验证错误。
Python 类型提示简介
掌握 Pydantic 的关键在于理解 Python 的类型提示。类型提示不仅为代码提供了更好的可读性,还能借助静态类型检查工具(例如 PEP-484 中介绍的规范)提高开发效率。
为什么
在 Java、C# 等强类型语言中,变量和方法参数的类型是必不可少的。引入类型提示的目的是在不影响 Python 动态特性的前提下,为代码提供额外的类型信息,帮助 IDE 提供更智能的自动补全、静态代码检查以及重构支持。
基本用法
  • 简单变量声明:  
    1. count: int = 0
    复制代码

  • 复合类型:  
    1. from typing import Union, List
    2. value: Union[int, str] = 42
    3. numbers: List[int] = [1, 2, 3]
    复制代码

通过这种方式,开发者可以清晰地描述数据类型,从而使代码在开发和维护过程中更具可读性和可维护性。
Pydantic 的基本用法
Pydantic 的核心在于 BaseModel 类。通过继承 BaseModel,你可以定义一个数据模型,并利用 Python 的类型提示来描述每个字段的类型。当数据不符合预期时,Pydantic 会自动抛出 ValidationError,让你可以迅速定位问题。
例如:
  1. from pydantic import BaseModel

  2. class User(BaseModel):
  3.     id: int
  4.     name: str = "Anonymous"

  5. user = User(id="123")  # 字符串 "123" 会自动转换为整数
  6. print(user.dict())     # 输出: {'id': 123, 'name': 'Anonymous'}
复制代码

在数据解析失败的情况下,Pydantic 会明确指出哪一个字段的数据不合法,从而大大简化调试工作。
进一步探索
Validators
在某些情况下,仅依赖类型提示可能不足以满足复杂的数据校验需求。例如,我们希望确保 room_id 是一个 正整数,而不是负数或零。此外,sending_delay 应该在 1 到 10 之间,否则会影响程序的运行逻辑。
在 Pydantic 中,我们可以使用 @field_validator(Pydantic v2)或 @validator(Pydantic v1)来自定义字段验证逻辑。以下是一个具体的示例:
  1. from pydantic import BaseModel, field_validator, ValidationError

  2. class Config(BaseModel):
  3.     room_id: int
  4.     sending_delay: int
  5.    
  6.     @field_validator("room_id")
  7.     @classmethod
  8.     def check_room_id(cls, value):
  9.         """确保 room_id 是正整数"""
  10.         if value <= 0:
  11.             raise ValueError("room_id 必须是一个正整数")
  12.         return value

  13.     @field_validator("sending_delay")
  14.     @classmethod
  15.     def check_sending_delay(cls, value):
  16.         """确保 sending_delay 在 1 到 10 之间"""
  17.         if not (1 <= value <= 10):
  18.             raise ValueError("sending_delay 必须在 1 到 10 之间")
  19.         return value

  20. # 测试
  21. try:
  22.     config = Config(room_id=-100, sending_delay=5)  # room_id 不合法
  23. except ValidationError as e:
  24.     print(e)

  25. try:
  26.     config = Config(room_id=123, sending_delay=15)  # sending_delay 不合法
  27. except ValidationError as e:
  28.     print(e)

  29. try:
  30.     config = Config(room_id=456, sending_delay=3)  # 合法数据
  31.     print("验证成功:", config)
  32. except ValidationError as e:
  33.     print(e)
复制代码

通过利用 Pydantic,你不仅可以避免繁琐的手写验证代码,还能借助 Python 类型提示带来的诸多好处,使你的项目更加健壮和易于维护。无论是在构建 API 接口、配置管理还是数据解析方面,Pydantic 都提供了一个既直观又高效的解决方案。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|RealDevClub ( 沪ICP备2024093864号-1 )

GMT+8, 5-11-2025 04:33 , Processed in 0.063788 second(s), 20 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表