Python库之Pydantic

发布时间 2023-10-27 20:43:56作者: Python喵

背景介绍

Pydantic 是一个Python库,用于数据验证和设置管理。它最初是为了弥补Python标准库在数据验证方面的不足而设计的。与其他数据验证库(如 Marshmallow、Cerberus)相比,Pydantic 强调类型提示和类型安全,使其与 Python 3.6+ 的类型系统无缝集成。Pydantic 在现代Web框架(如 FastAPI)和数据科学项目中非常流行。

简单解释

Pydantic 允许你定义数据模型,这些模型会自动验证输入数据的结构和类型。你只需定义一个类,用 Python 的类型提示标注其字段,Pydantic 就会为你处理验证和序列化。与使用JSON Schema或OpenAPI进行手动验证相比,这大大简化了数据验证过程。同时,Pydantic 也提供了强大的数据转换能力,能将复杂数据结构(如 JSON、字典)轻易转换为Python对象。

场景:API 参数验证和转换在电子商务平台

背景

假设你正在开发一个电子商务平台的后端服务,该服务提供了一个API端点,允许客户提交订单。每个订单都有多个字段,如产品ID、数量、支付方式等。你希望验证这些输入参数的有效性并转换为内部使用的Python对象。

常见技术对比

  • 手动验证:你可以在代码中手动检查每个字段,但这样做很冗长,容易出错。
  • JSON Schema:提供一种结构化的验证方法,但需要额外的定义和解析步骤。
  • Marshmallow:也是一种常用于数据验证的库,但与Pydantic相比,它更侧重于序列化和反序列化,而不是类型安全。

Pydantic 的实际应用

使用 Pydantic,你可以定义一个 Order模型来自动完成这些工作。

from pydantic import BaseModel, Field

class Order(BaseModel):
    product_id: int = Field(..., gt=0)
    quantity: int = Field(..., gt=0, le=100)
    payment_method: str = Field(..., regex="^(credit_card|paypal)$")

功能

  1. 类型检查: product_idquantity必须是整数。
  2. 范围验证: product_id必须大于0,quantity必须在1到100之间。
  3. 正则匹配: payment_method只能是 "credit_card" 或 "paypal"。

使用

当客户通过API提交一个订单时,你只需将输入数据传递给这个 Order模型。如果数据无效,Pydantic 将自动抛出一个详细的错误,指出哪个字段无效以及为什么。

order_data = {
    "product_id": 1,
    "quantity": 50,
    "payment_method": "credit_card"
}

try:
    order = Order(**order_data)
except ValidationError as e:
    print(e.json())

这种方式使得代码更简洁,更易于维护,同时提供了强类型和自动验证的优点。与手动验证或使用其他库相比,Pydantic 提供了一个更为高效和直观的解决方案。

示例:用户注册API与Pydantic的数据验证

代码设置

在这个示例中,我们使用 FastAPI 构建一个简单的用户注册 API。FastAPI 与 Pydantic 集成非常紧密,用于请求和响应模型的验证。我们将比较使用 Pydantic 和手动验证的差异。

首先,我们导入必要的模块并设置 FastAPI 应用。

from fastapi import FastAPI, HTTPException
from pydantic import BaseModel, EmailStr, Field
from typing import Optional

app = FastAPI()

Pydantic 数据模型

接下来,我们使用 Pydantic 定义一个用户注册的数据模型。

class UserRegister(BaseModel):
    username: str = Field(..., min_length=3, max_length=50)
    email: EmailStr
    password: str = Field(..., min_length=8)
    age: Optional[int] = Field(None, ge=18)

在这个模型中,我们定义了如下字段和验证规则:

  • username: 字符串类型,长度必须在3到50字符之间。
  • email: 必须是有效的电子邮件地址。
  • password: 字符串类型,至少包含8个字符。
  • age: 整数类型,可选,但如果提供必须大于等于18。

FastAPI 路由与验证

使用 Pydantic 模型,我们可以很容易地在 FastAPI 路由中进行数据验证。

@app.post("/register/")
def register(user: UserRegister):
    return {"username": user.username, "email": user.email}

对比:手动验证

如果不使用 Pydantic,数据验证会变得复杂和冗长。例如:

@app.post("/register_manual/")
def register_manual(username: str, email: str, password: str, age: Optional[int] = None):
    if len(username) < 3 or len(username) > 50:
        raise HTTPException(status_code=400, detail="Invalid username length")

    # ...其他字段验证

    return {"username": username, "email": email}

在这个手动验证的示例中,我们需要为每个字段写多行验证代码,这显然不如使用 Pydantic 效率高。

总结

使用 Pydantic,我们能以更少的代码,更高的可读性和更好的维护性来完成数据验证。同时,它与 FastAPI 的集成也使得开发更加高效。与手动验证相比,Pydantic 提供了一种更加优雅和强大的解决方案。

部分概念解释

Marshmallow

Marshmallow 是一个用于对象序列化/反序列化的 Python 库。尽管它也提供数据验证功能,但它的主要重点是在复杂数据类型(如对象)与 Python 数据类型(如字典)之间转换。这对于 API 开发和数据处理任务非常有用。

Cerberus

Cerberus 是一个轻量级但强大的 Python 数据验证库。它主要用于验证传入的数据结构,特别是 JSON、YAML 和 XML 的嵌套或扁平化数据。与 Marshmallow 和 Pydantic 相比,Cerberus 更侧重于灵活性和自定义。

类型提示(Type Hinting)

类型提示是 Python 3.5+ 版本引入的一个特性,允许开发者为变量、函数参数和函数返回值指定预期的数据类型。这有助于代码可读性和自文档化,同时也能在开发过程中提供更好的 IDE 支持和错误检查。

类型安全(Type Safety)

类型安全是指编程语言中变量或对象的数据类型在其生命周期内保持一致,或者在进行不安全操作时编译器或运行时环境能提供明确的警告或错误。在类型安全的环境中,尝试进行不匹配类型的操作(如将字符串加到整数)通常会导致编译或运行时错误。

FastAPI

FastAPI 是一个现代、快速(高性能)的 Python Web 框架,用于构建 API。它基于 Starlette 和 Pydantic,提供了高性能的数据验证和类型检查。FastAPI 支持自动生成交互式 API 文档,利用 Python 的类型提示来提供强类型支持,从而提高开发效率和减少错误。

数据模型

数据模型是一种结构,用于定义和组织数据的各个方面,包括其格式、字段、关系等。在编程中,数据模型通常用类或结构体表示,其中的属性或成员变量代表数据字段。数据模型不仅描述了数据的结构,也可能包括验证规则、默认值和其他元数据。

用 Python 的类型提示标注其字段

在 Python 中,你可以使用类型提示来标注类或数据模型的字段。这意味着你可以明确指定每个字段应该是什么类型的数据。例如,如果你有一个名为 User 的数据模型,你可能会这样标注其字段:

class User:
    username: str
    age: int

在这个例子中,username 字段被标注为字符串(str),而 age 字段被标注为整数(int)。

序列化

序列化是将复杂数据结构(如对象、数组、字典等)转换为简单数据格式(如字符串或字节流)的过程。这样做是为了便于存储或传输。反序列化是相反的过程,将简单数据格式还原为复杂数据结构。

JSON Schema

JSON Schema 是一种用于描述 JSON 数据格式的模式或蓝图。它提供了一种机制,用于定义 JSON 文档的结构、类型、约束和语义。通过使用 JSON Schema,你可以自动验证 JSON 文档是否满足预定义的条件。

OpenAPI

OpenAPI(之前称为 Swagger)是一个用于 API 规范的开源框架。它使用 JSON 或 YAML 格式来描述 API 的所有方面,包括端点、请求参数、响应、错误代码等。OpenAPI 允许你自动生成文档、客户端 SDK 生成、服务器存根和其他代码片段,从而提高开发效率和准确性。

BaseModel

BaseModel 是 Pydantic 库中的一个基础类,用于定义数据模型。继承自 BaseModel 的类将自动获得数据验证、序列化和其他便利功能。

Field

Field 是 Pydantic 中用于额外配置模型字段的函数。它可以用于设置默认值、添加验证条件、指定别名等。

class Order(BaseModel):

这是一个使用 Pydantic 的 BaseModel 定义的数据模型类,名为 Order。该类可以用于验证订单相关的数据,如产品ID、数量和支付方式等。

Field(..., gt=0)

这是一个使用 Field 函数配置的字段,其中 gt=0 指定了一个验证条件:该字段的值必须大于0。

Field(..., gt=0, le=100)

这里,除了要求字段值大于0(gt=0)之外,还添加了一个额外的条件:字段值必须小于或等于100(le=100)。

Field(..., regex="^(credit_card|paypal)$")

这是一个用正则表达式配置的字段。regex="^(credit_card|paypal)$" 指定了该字段只能接受 "credit_card" 或 "paypal" 这两个具体的字符串值。

这些 Field 的用法允许你在定义数据模型时添加详细的验证规则,从而确保数据的质量和安全性。

order = Order(**order_data) 中的 ** 是什么?

在 Python 中,** 符号用于解包字典,将其键值对作为命名参数传递给函数或构造器。在这里,Order(**order_data) 会将 order_data 字典中的所有键值对传递给 Order 类的构造器,以便进行数据验证和实例化。

from fastapi import FastAPI, HTTPException 是什么?

这是一个导入语句,从 FastAPI 框架中导入 FastAPIHTTPException 类。FastAPI 是用于创建 API 的主要类,而 HTTPException 用于在应用中抛出 HTTP 错误。

EmailStr 是什么?

EmailStr 是 Pydantic 提供的一个类型,用于验证一个字符串是否符合电子邮件地址的格式。如果字符串不是有效的电子邮件地址,Pydantic 将抛出一个验证错误。

from typing import Optional 是什么?

这是一个导入语句,从 Python 的标准库 typing 模块中导入 Optional 类型。Optional 用于标注一个类型可能是 None,即它可以是某个类型 TNone

app = FastAPI() 是什么?

这是 FastAPI 框架的初始化语句,创建了一个 FastAPI 类的实例,并将其存储在变量 app 中。该实例用于定义和配置你的 API,包括路由、中间件、依赖等。

Field(..., min_length=3, max_length=50) 是什么?

这是一个使用 Pydantic 的 Field 函数配置的字段,其中 min_length=3max_length=50 指定了字符串字段的最小和最大长度。... 表示该字段是必填的。如果输入数据不满足这些条件,Pydantic 会抛出一个验证错误。

Field(None, ge=18) 是什么?

这是使用 Field 配置的一个可选字段。None 表示该字段是可选的,并且默认值为 Nonege=18 指定了一个验证条件:如果该字段有值,那么值必须大于或等于 18。

@app.post("/register/") 是什么?

这是一个 FastAPI 的路由装饰器,用于定义一个处理 POST 请求的 API 端点。"/register/" 是该端点的路径。当客户端发送一个 POST 请求到这个路径时,FastAPI 会自动调用装饰器下面的函数来处理该请求。这个函数通常用于接收和处理客户端传来的数据,并返回响应。