跳转至

警告

“🚧 正在进行中” 此页面正在进行中。

JSON

Json Parsing

JSON 解析

API 文档

pydantic.main.BaseModel.model_validate_json pydantic.type_adapter.TypeAdapter.validate_json pydantic_core.from_json

Pydantic 提供了内置的 JSON 解析,这有助于实现:

  • 显著的性能提升,无需使用第三方库的成本

  • 支持自定义错误

  • strict 规范的支持

以下是通过 model_validate_json 方法使用 Pydantic 的内置 JSON 解析的示例,展示了在解析与模型的类型注解不匹配的 JSON 数据时对 strict 规范的支持:

from datetime import date
from typing import Tuple

from pydantic import BaseModel, ConfigDict, ValidationError


class Event(BaseModel):
    model_config = ConfigDict(strict=True)

    when: date
    where: Tuple[int, int]


json_data = '{"when": "1987-01-28", "where": [51, -1]}'
print(Event.model_validate_json(json_data))  # (1)!
#> when=datetime.date(1987, 1, 28) where=(51, -1)

try:
    Event.model_validate({'when': '1987-01-28', 'where': [51, -1]})  # (2)!
except ValidationError as e:
    print(e)
    """
    2 validation errors for Event
    when
      Input should be a valid date [type=date_type, input_value='1987-01-28', input_type=str]
    where
      Input should be a valid tuple [type=tuple_type, input_value=[51, -1], input_type=list]
    """
  1. JSON 没有 date 或元组类型,但 Pydantic 知道这一点,因此在直接解析 JSON 时允许字符串和数组分别作为输入。

  2. 如果向 model_validate 方法传递相同的值,Pydantic 将引发验证错误,因为已启用 strict 配置。

在 v2.5.0 及更高版本中,Pydantic 使用 jiter ,一个快速且可迭代的 JSON 解析器,来解析 JSON 数据。使用 jiterserde 相比,性能有了适度的提高,未来还会更好。

jiter JSON 解析器几乎完全与 serde JSON 解析器兼容,一个明显的增强是 jiter 支持反序列化 infNaN 值。未来, jiter 旨在使支持验证错误能够包括原始 JSON 输入中包含无效值的位置。

部分 JSON 解析

从 v2.7.0 开始,Pydantic 的 JSON 解析器提供了对部分 JSON 解析的支持,这是通过 pydantic_core.from_json 暴露的。以下是此功能的示例:

from pydantic_core import from_json

partial_json_data = '["aa", "bb", "c'  # (1)!

try:
    result = from_json(partial_json_data, allow_partial=False)
except ValueError as e:
    print(e)  # (2)!
    #> EOF while parsing a string at line 1 column 15

result = from_json(partial_json_data, allow_partial=True)
print(result)  # (3)!
#> ['aa', 'bb']
  1. JSON 列表不完整——缺少一个结束的 "]

  2. allow_partial 设置为 False (默认值)时,会发生解析错误。

  3. allow_partial 设置为 True 时,部分输入成功反序列化。

这也适用于反序列化部分字典。例如:

from pydantic_core import from_json

partial_dog_json = '{"breed": "lab", "name": "fluffy", "friends": ["buddy", "spot", "rufus"], "age'
dog_dict = from_json(partial_dog_json, allow_partial=True)
print(dog_dict)
#> {'breed': 'lab', 'name': 'fluffy', 'friends': ['buddy', 'spot', 'rufus']}

提示

"验证 LLM 输出" 此功能对于验证 LLM 输出特别有益。我们写了一些关于这个主题的博客文章,你可以在这里找到它们。

在 Pydantic 的未来版本中,我们期望通过 Pydantic 的其他 JSON 验证功能( pydantic.main.BaseModel.model_validate_json pydantic.type_adapter.TypeAdapter.validate_json )或模型配置来扩展对该功能的支持。敬请关注🚀!

目前,你可以结合使用 pydantic_core.from_json pydantic.main.BaseModel.model_validate 来达到相同的效果。以下是一个示例:

from pydantic_core import from_json

from pydantic import BaseModel


class Dog(BaseModel):
    breed: str
    name: str
    friends: list


partial_dog_json = '{"breed": "lab", "name": "fluffy", "friends": ["buddy", "spot", "rufus"], "age'
dog = Dog.model_validate(from_json(partial_dog_json, allow_partial=True))
print(repr(dog))
#> Dog(breed='lab', name='fluffy', friends=['buddy', 'spot', 'rufus'])

提示

为了使部分 JSON 解析能够可靠地工作,模型上的所有字段都应该有默认值。

查看以下示例,以更深入地了解如何使用默认值进行部分 JSON 解析:

示例

“使用部分 JSON 解析的默认值”

from typing import Any, Optional, Tuple

import pydantic_core
from typing_extensions import Annotated

from pydantic import BaseModel, ValidationError, WrapValidator


def default_on_error(v, handler) -> Any:
    """
    Raise a PydanticUseDefault exception if the value is missing.

    This is useful for avoiding errors from partial
    JSON preventing successful validation.
    """
    try:
        return handler(v)
    except ValidationError as exc:
        # there might be other types of errors resulting from partial JSON parsing
        # that you allow here, feel free to customize as needed
        if all(e['type'] == 'missing' for e in exc.errors()):
            raise pydantic_core.PydanticUseDefault()
        else:
            raise


class NestedModel(BaseModel):
    x: int
    y: str


class MyModel(BaseModel):
    foo: Optional[str] = None
    bar: Annotated[
        Optional[Tuple[str, int]], WrapValidator(default_on_error)
    ] = None
    nested: Annotated[
        Optional[NestedModel], WrapValidator(default_on_error)
    ] = None


m = MyModel.model_validate(
    pydantic_core.from_json('{"foo": "x", "bar": ["world",', allow_partial=True)
)
print(repr(m))
#> MyModel(foo='x', bar=None, nested=None)


m = MyModel.model_validate(
    pydantic_core.from_json(
        '{"foo": "x", "bar": ["world", 1], "nested": {"x":', allow_partial=True
    )
)
print(repr(m))
#> MyModel(foo='x', bar=('world', 1), nested=None)

字符串缓存

从 v2.7.0 开始,Pydantic 的 JSON 解析器提供了对配置 Python 字符串在 JSON 解析和验证期间如何缓存的支持(当 Python 字符串在 Python 验证期间从 Rust 字符串构建时,例如在 strip_whitespace=True 之后)。 cache_strings 设置通过 model config pydantic_core.from_json 都暴露了出来。

cache_strings 设置可以取以下任何值:

  • True'all' (默认):缓存所有字符串

  • 'keys' :仅缓存字典键,仅在与 pydantic_core.from_json 一起使用或使用 Json 解析 JSON 时适用

  • False'none' :不缓存

使用字符串缓存功能会提高性能,但会略微增加内存使用量。

注意

“字符串缓存详细信息”

  1. Strings are cached using a fully associative cache with a size of 16,384.
  2. Only strings where len(string) < 64 are cached.
  3. There is some overhead to looking up the cache, which is normally worth it to avoid constructing strings. However, if you know there will be very few repeated strings in your data, you might get a performance boost by disabling this setting with cache_strings=False.

JSON Serialization

JSON 序列化

API 文档

pydantic.main.BaseModel.model_dump_json

pydantic.type_adapter.TypeAdapter.dump_json

pydantic_core.to_json

有关 JSON 序列化的更多信息,请参阅序列化概念页面。


本文总阅读量