为什么要使用 Pydantic?¶
如今,Pydantic 每月被下载 多次,并被世界上一些最大和最知名的组织使用。
很难知道自从六年前 Pydantic 问世以来,为什么这么多人采用了它,但这里有一些猜测。
类型提示驱动的模式验证¶
Pydantic 验证所依据的模式通常由 Python 类型提示 定义。
类型提示非常适合这一点,因为如果您正在编写现代 Python,您已经知道如何使用它们。使用类型提示还意味着 Pydantic 与静态类型工具(如 mypy 和 Pyright)和 IDE(如 PyCharm 和 VSCode)良好集成。
示例 - 仅类型提示
from typing import Annotated, Literal
from annotated_types import Gt
from pydantic import BaseModel
class Fruit(BaseModel):
name: str # (1)!
color: Literal['red', 'green'] # (2)!
weight: Annotated[float, Gt(0)] # (3)!
bazam: dict[str, list[tuple[int, bool, float]]] # (4)!
print(
Fruit(
name='Apple',
color='red',
weight=4.2,
bazam={'foobar': [(1, True, 0.1)]},
)
)
#> name='Apple' color='red' weight=4.2 bazam={'foobar': [(1, True, 0.1)]}
name
字段只是用str
注释的 — 允许任何字符串。Literal
类型用于强制color
只能是'red'
或'green'
。- 即使我们想要应用 Python 类型中未封装的约束,我们也可以使用
Annotated
和annotated-types
来强制约束,同时仍然保持类型支持。 - 我并不是声称 “bazam” 真正是水果的属性,而是为了展示可以轻松验证任意复杂类型。
了解更多
请参阅 关于支持类型的文档。
性能¶
Pydantic 的核心验证逻辑是在一个单独的包(pydantic-core
)中实现的,其中大多数类型的验证是在 Rust 中实现的。
因此,Pydantic 是 Python 最快的数据验证库之一。
性能示例 - Pydantic 与专用代码
一般来说,专用代码应该比通用验证器快得多,但在本例中,当解析 JSON 和验证 URL 时,Pydantic 比专用代码快 >300%。
import json
import timeit
from urllib.parse import urlparse
import requests
from pydantic import HttpUrl, TypeAdapter
reps = 7
number = 100
r = requests.get('https://api.github.com/emojis')
r.raise_for_status()
emojis_json = r.content
def emojis_pure_python(raw_data):
data = json.loads(raw_data)
output = {}
for key, value in data.items():
assert isinstance(key, str)
url = urlparse(value)
assert url.scheme in ('https', 'http')
output[key] = url
emojis_pure_python_times = timeit.repeat(
'emojis_pure_python(emojis_json)',
globals={
'emojis_pure_python': emojis_pure_python,
'emojis_json': emojis_json,
},
repeat=reps,
number=number,
)
print(f'pure python: {min(emojis_pure_python_times) / number * 1000:0.2f}ms')
#> pure python: 5.32ms
type_adapter = TypeAdapter(dict[str, HttpUrl])
emojis_pydantic_times = timeit.repeat(
'type_adapter.validate_json(emojis_json)',
globals={
'type_adapter': type_adapter,
'HttpUrl': HttpUrl,
'emojis_json': emojis_json,
},
repeat=reps,
number=number,
)
print(f'pydantic: {min(emojis_pydantic_times) / number * 1000:0.2f}ms')
#> pydantic: 1.54ms
print(
f'Pydantic {min(emojis_pure_python_times) / min(emojis_pydantic_times):0.2f}x faster'
)
#> Pydantic 3.45x faster
与用编译语言编写的其他以性能为中心的库不同,Pydantic 还出色地支持通过 函数式验证器 自定义验证。
了解更多
Samuel Colvin 在 PyCon 2023 上的演讲 解释了 pydantic-core
的工作原理以及它如何与 Pydantic 集成。
序列化¶
Pydantic 提供了以三种方式序列化模型的功能
- 转换为由关联的 Python 对象组成的 Python
dict
。 - 转换为仅由 “jsonable” 类型组成的 Python
dict
。 - 转换为 JSON 字符串。
在所有三种模式下,都可以通过排除特定字段、排除未设置字段、排除默认值和排除 None
值来自定义输出。
示例 - 3 种序列化方式
from datetime import datetime
from pydantic import BaseModel
class Meeting(BaseModel):
when: datetime
where: bytes
why: str = 'No idea'
m = Meeting(when='2020-01-01T12:00', where='home')
print(m.model_dump(exclude_unset=True))
#> {'when': datetime.datetime(2020, 1, 1, 12, 0), 'where': b'home'}
print(m.model_dump(exclude={'where'}, mode='json'))
#> {'when': '2020-01-01T12:00:00', 'why': 'No idea'}
print(m.model_dump_json(exclude_defaults=True))
#> {"when":"2020-01-01T12:00:00","where":"home"}
了解更多
请参阅 关于序列化的文档。
JSON 模式¶
可以为任何 Pydantic 模式生成 JSON 模式 — 从而实现自我文档化的 API 以及与各种支持 JSON 模式格式的工具集成。
示例 - JSON 模式
from datetime import datetime
from pydantic import BaseModel
class Address(BaseModel):
street: str
city: str
zipcode: str
class Meeting(BaseModel):
when: datetime
where: Address
why: str = 'No idea'
print(Meeting.model_json_schema())
"""
{
'$defs': {
'Address': {
'properties': {
'street': {'title': 'Street', 'type': 'string'},
'city': {'title': 'City', 'type': 'string'},
'zipcode': {'title': 'Zipcode', 'type': 'string'},
},
'required': ['street', 'city', 'zipcode'],
'title': 'Address',
'type': 'object',
}
},
'properties': {
'when': {'format': 'date-time', 'title': 'When', 'type': 'string'},
'where': {'$ref': '#/$defs/Address'},
'why': {'default': 'No idea', 'title': 'Why', 'type': 'string'},
},
'required': ['when', 'where'],
'title': 'Meeting',
'type': 'object',
}
"""
Pydantic 符合最新版本的 JSON 模式规范 (2020-12),该规范与 OpenAPI 3.1 兼容。
了解更多
请参阅 关于 JSON 模式的文档。
严格模式和数据强制转换¶
默认情况下,Pydantic 对常见的错误类型具有容错性,并将数据强制转换为正确的类型 — 例如,传递给 int
字段的数字字符串将被解析为 int
。
Pydantic 还具有 严格模式,其中类型不会被强制转换,并且除非输入数据与预期模式完全匹配,否则会引发验证错误。
但是,当验证 JSON 数据时,严格模式将非常无用,因为 JSON 没有与许多常见的 Python 类型(如 datetime
、UUID
或 bytes
)匹配的类型。
为了解决这个问题,Pydantic 可以一步解析和验证 JSON。这允许合理的数据转换(例如,当将字符串解析为 datetime
对象时)。由于 JSON 解析是在 Rust 中实现的,因此它的性能也非常出色。
示例 - 真正有用的严格模式
from datetime import datetime
from pydantic import BaseModel, ValidationError
class Meeting(BaseModel):
when: datetime
where: bytes
m = Meeting.model_validate({'when': '2020-01-01T12:00', 'where': 'home'})
print(m)
#> when=datetime.datetime(2020, 1, 1, 12, 0) where=b'home'
try:
m = Meeting.model_validate(
{'when': '2020-01-01T12:00', 'where': 'home'}, strict=True
)
except ValidationError as e:
print(e)
"""
2 validation errors for Meeting
when
Input should be a valid datetime [type=datetime_type, input_value='2020-01-01T12:00', input_type=str]
where
Input should be a valid bytes [type=bytes_type, input_value='home', input_type=str]
"""
m_json = Meeting.model_validate_json(
'{"when": "2020-01-01T12:00", "where": "home"}'
)
print(m_json)
#> when=datetime.datetime(2020, 1, 1, 12, 0) where=b'home'
了解更多
请参阅 关于严格模式的文档。
数据类、TypedDicts 等¶
Pydantic 提供了四种创建模式并执行验证和序列化的方法
BaseModel
— Pydantic 自己的超类,通过实例方法提供许多常用实用程序。- Pydantic 数据类 — 标准数据类的包装器,执行额外的验证。
TypeAdapter
— 一种通用的方式,用于调整任何类型以进行验证和序列化。这允许验证TypedDict
和NamedTuple
等类型,以及简单类型(如int
或timedelta
)— 所有支持的类型 都可以与TypeAdapter
一起使用。validate_call
— 一个在调用函数时执行验证的装饰器。
示例 - 基于 TypedDict
的模式
from datetime import datetime
from typing_extensions import NotRequired, TypedDict
from pydantic import TypeAdapter
class Meeting(TypedDict):
when: datetime
where: bytes
why: NotRequired[str]
meeting_adapter = TypeAdapter(Meeting)
m = meeting_adapter.validate_python( # (1)!
{'when': '2020-01-01T12:00', 'where': 'home'}
)
print(m)
#> {'when': datetime.datetime(2020, 1, 1, 12, 0), 'where': b'home'}
meeting_adapter.dump_python(m, exclude={'where'}) # (2)!
print(meeting_adapter.json_schema()) # (3)!
"""
{
'properties': {
'when': {'format': 'date-time', 'title': 'When', 'type': 'string'},
'where': {'format': 'binary', 'title': 'Where', 'type': 'string'},
'why': {'title': 'Why', 'type': 'string'},
},
'required': ['when', 'where'],
'title': 'Meeting',
'type': 'object',
}
"""
- 用于
TypedDict
的TypeAdapter
执行验证,它还可以使用validate_json
直接验证 JSON 数据。 dump_python
将TypedDict
序列化为 python 对象,它还可以使用dump_json
序列化为 JSON。TypeAdapter
还可以生成 JSON 模式。
自定义¶
函数式验证器和序列化器,以及用于自定义类型的强大协议,意味着可以基于每个字段或每个类型自定义 Pydantic 的操作方式。
自定义示例 - 包装验证器
“包装验证器” 是 Pydantic V2 中的新功能,是自定义验证的最强大方法之一。
from datetime import datetime, timezone
from typing import Any
from pydantic_core.core_schema import ValidatorFunctionWrapHandler
from pydantic import BaseModel, field_validator
class Meeting(BaseModel):
when: datetime
@field_validator('when', mode='wrap')
def when_now(
cls, input_value: Any, handler: ValidatorFunctionWrapHandler
) -> datetime:
if input_value == 'now':
return datetime.now()
when = handler(input_value)
# in this specific application we know tz naive datetimes are in UTC
if when.tzinfo is None:
when = when.replace(tzinfo=timezone.utc)
return when
print(Meeting(when='2020-01-01T12:00+01:00'))
#> when=datetime.datetime(2020, 1, 1, 12, 0, tzinfo=TzInfo(+01:00))
print(Meeting(when='now'))
#> when=datetime.datetime(2032, 1, 2, 3, 4, 5, 6)
print(Meeting(when='2020-01-01T12:00'))
#> when=datetime.datetime(2020, 1, 1, 12, 0, tzinfo=datetime.timezone.utc)
生态系统¶
在撰写本文时,GitHub 上有 466,400 个存储库,PyPI 上有 8,119 个包依赖于 Pydantic。
一些依赖于 Pydantic 的著名库
huggingface/transformers
138,570 星hwchase17/langchain
99,542 星tiangolo/fastapi
80,497 星apache/airflow
38,577 星lm-sys/FastChat
37,650 星microsoft/DeepSpeed
36,521 星OpenBB-finance/OpenBBTerminal
35,971 星gradio-app/gradio
35,740 星ray-project/ray
35,176 星pola-rs/polars
31,698 星Lightning-AI/lightning
28,902 星mindsdb/mindsdb
27,141 星embedchain/embedchain
24,379 星pynecone-io/reflex
21,558 星heartexlabs/label-studio
20,571 星Sanster/lama-cleaner
20,313 星mlflow/mlflow
19,393 星RasaHQ/rasa
19,337 星spotDL/spotify-downloader
18,604 星chroma-core/chroma
17,393 星airbytehq/airbyte
17,120 星openai/evals
15,437 星tiangolo/sqlmodel
15,127 星ydataai/ydata-profiling
12,687 星pyodide/pyodide
12,653 星dagster-io/dagster
12,440 星PaddlePaddle/PaddleNLP
12,312 星matrix-org/synapse
11,857 星lucidrains/DALLE2-pytorch
11,207 星great-expectations/great_expectations
10,164 星modin-project/modin
10,002 星aws/serverless-application-model
9,402 星sqlfluff/sqlfluff
8,535 星replicate/cog
8,344 星autogluon/autogluon
8,326 星lucidrains/imagen-pytorch
8,164 星brycedrennan/imaginAIry
8,050 星vitalik/django-ninja
7,685 星NVlabs/SPADE
7,632 星bridgecrewio/checkov
7,340 星bentoml/BentoML
7,322 星skypilot-org/skypilot
7,113 星apache/iceberg
6,853 星deeppavlov/DeepPavlov
6,777 星PrefectHQ/marvin
5,454 星NVIDIA/NeMo-Guardrails
4,383 星microsoft/FLAML
4,035 星jina-ai/discoart
3,846 星docarray/docarray
3,007 星aws-powertools/powertools-lambda-python
2,980 星roman-right/beanie
2,172 星art049/odmantic
1,096 星
更多使用 Pydantic 的库可以在 Kludex/awesome-pydantic
中找到。
使用 Pydantic 的组织¶
一些使用 Pydantic 的著名公司和组织,以及关于我们如何知道他们正在使用 Pydantic 的原因/方式的评论。
以下组织之所以被包括在内,是因为它们符合以下一个或多个标准
- 在公共存储库中使用 Pydantic 作为依赖项。
- 将流量从组织内部域引导至 Pydantic 文档站点 — 未包含特定引荐来源,因为它们通常不在公共领域。
- Pydantic 团队与组织雇用的工程师之间就组织内部 Pydantic 的使用情况进行直接沟通。
我们在适当且已在公共领域的情况下包含了一些额外详细信息。
Adobe¶
adobe/dy-sql
使用 Pydantic。
Amazon 和 AWS¶
- powertools-lambda-python
- awslabs/gluonts
- AWS 在 2022 年 赞助了 Samuel Colvin 5,000 美元 用于开发 Pydantic
Anthropic¶
anthropics/anthropic-sdk-python
使用 Pydantic。
Apple¶
(基于上述标准)
ASML¶
(基于上述标准)
AstraZeneca¶
AstraZeneca GitHub 组织中的多个仓库 依赖于 Pydantic。
Cisco Systems¶
- Pydantic 列在他们的 RADKit 中使用的开源 报告中。
cisco/webex-assistant-sdk
Comcast¶
(基于上述标准)
Datadog¶
- 在
DataDog/integrations-core
和其他仓库中广泛使用 Pydantic - 与 Datadog 的工程师就他们如何使用 Pydantic 进行沟通。
Facebook¶
facebookresearch GitHub 组织中的多个仓库 依赖于 Pydantic。
GitHub¶
GitHub 在 2022 年赞助了 Pydantic 750 美元
Google¶
在 google/turbinia
和其他仓库中广泛使用 Pydantic。
HSBC¶
(基于上述标准)
IBM¶
IBM GitHub 组织中的多个仓库 依赖于 Pydantic。
Intel¶
(基于上述标准)
Intuit¶
(基于上述标准)
政府间气候变化专门委员会¶
推文 解释了 IPCC 如何使用 Pydantic。
JPMorgan¶
(基于上述标准)
Jupyter¶
Microsoft¶
- DeepSpeed 深度学习优化库广泛使用 Pydantic
- microsoft GitHub 组织中的多个仓库 依赖于 Pydantic,特别是他们的
- Pydantic 也 在 Azure GitHub 组织中被使用
- GitHub 上的 评论 表明 Microsoft 工程师正在将 Pydantic 作为 Windows 和 Office 的一部分使用
分子科学软件研究所¶
MolSSI GitHub 组织中的多个仓库 依赖于 Pydantic。
NASA¶
NASA GitHub 组织中的多个仓库 依赖于 Pydantic。
NASA 还在他们的 JWST 项目中通过 FastAPI 使用 Pydantic 来处理来自詹姆斯·韦伯太空望远镜的图像,请参阅 这条推文。
Netflix¶
Netflix GitHub 组织中的多个仓库 依赖于 Pydantic。
NSA¶
nsacyber/WALKOFF
仓库依赖于 Pydantic。
NVIDIA¶
NVIDIA GitHub 组织中的多个仓库 依赖于 Pydantic。
根据 他们的文档,他们的 “Omniverse Services” 依赖于 Pydantic。
OpenAI¶
根据 GitHub 上的 此 讨论,OpenAI 将 Pydantic 用于他们的 ChatCompletions API。
据传闻,OpenAI 在其内部服务中广泛使用 Pydantic。
Oracle¶
(基于上述标准)
Palantir¶
(基于上述标准)
Qualcomm¶
(基于上述标准)
Red Hat¶
(基于上述标准)
Revolut¶
据传闻,Revolut 的所有内部服务都是使用 FastAPI 构建的,因此也使用了 Pydantic。
Robusta¶
robusta-dev/robusta
仓库依赖于 Pydantic。
Salesforce¶
Salesforce 在 2022 年 赞助了 Samuel Colvin 10,000 美元 用于开发 Pydantic。
Starbucks¶
(基于上述标准)
Texas Instruments¶
(基于上述标准)
Twilio¶
(基于上述标准)
Twitter¶
Twitter 的 the-algorithm
仓库(他们 开源 了他们的推荐引擎)使用了 Pydantic。
英国内政部¶
(基于上述标准)