You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Pydantic中json_or_python_schema的json_schema属性用途及调用时机

关于Pydantic中core_schema.json_or_python_schema的json_schema字段疑问

问题背景

存在无法修改的外部类OriginalExternalClass,需要将其作为继承自Pydantic BaseModel的PydanticClassWithExternalClassMember类的字段。为规避使用arbitrary_types flag并实现该字段的类型校验与序列化能力,编写了如下代码:

from typing import Any
from pydantic_core import core_schema
import pydantic


class OriginalExternalClass:
    def __init__(self, a: int, b: str) -> None:
        self.a = a
        self.b = b


class PydanticExternalClass(OriginalExternalClass):
    @classmethod
    def __get_pydantic_core_schema__(
        cls,
        _source_type: Any,
        _handler: pydantic.GetCoreSchemaHandler,
    ) -> core_schema.CoreSchema:
        def json_schema(value: dict) -> OriginalExternalClass:
            # NEVER CALLED!!!
            print("json_schema called")
            result = OriginalExternalClass(**value)

            return result

        def python_schema(
            value: OriginalExternalClass,
        ) -> OriginalExternalClass:
            print("python_schema called")
            if isinstance(value, dict):
                value = OriginalExternalClass(**value)

            if not isinstance(value, OriginalExternalClass):
                raise pydantic.ValidationError(
                    msg="Expected a `ExternalClass` instance",
                    loc=("third_party_type",),
                    type=OriginalExternalClass,
                )

            return value

        def serialization(value: OriginalExternalClass) -> dict:
            print("serialization called")
            return {"a": value.a, "b": value.b}

        return core_schema.json_or_python_schema(
            json_schema=core_schema.no_info_plain_validator_function(json_schema),
            python_schema=core_schema.no_info_plain_validator_function(python_schema),
            serialization=core_schema.plain_serializer_function_ser_schema(
                serialization
            ),
        )


class PydanticClassWithExternalClassMember(pydantic.BaseModel):
    x: PydanticExternalClass

测试情况

执行以下测试代码时,发现json_schema函数从未被调用:

print(
    "m1 = PydanticClassWithExternalClassMember(x=PydanticExternalClass(1, 'basgsadf'))"
)
m1 = PydanticClassWithExternalClassMember(x=PydanticExternalClass(1, "basgsadf"))
print("d = m1.model_dump()")
d = m1.model_dump()
print("m1 = PydanticClassWithExternalClassMember(**d)")
m1 = PydanticClassWithExternalClassMember(**d)

输出结果:

m1 = PydanticClassWithExternalClassMember(x=PydanticExternalClass(1, 'basgsadf'))
python_schema called
d = m1.model_dump()
serialization called
m1 = PydanticClassWithExternalClassMember(**d)
python_schema called

核心疑问

需要明确:

  1. core_schema.json_or_python_schema的json_schema属性的用途是什么?
  2. 该属性对应的函数何时会被调用?

解答

1. json_schema的用途

json_schema是json_or_python_schema专门用于处理JSON兼容原生数据的校验与转换逻辑,负责将JSON解析后的纯字典、字符串、数字等原生类型,转换为目标Python对象(这里是OriginalExternalClass实例)。它和python_schema分工明确:python_schema处理已有的Python对象(包括字典形式的Python参数),json_schema则专注于JSON反序列化场景的输入。

2. json_schema的触发时机

json_schema会在以下场景中被调用:

  • 使用model_validate_json()方法直接传入JSON字符串时:此时输入是纯JSON格式的数据,Pydantic会优先走json_schema路径处理
  • 当通过model_validate()传入JSON兼容字典,且明确指定from_attributes=False(默认值),同时Pydantic判定该场景属于JSON反序列化时

为什么测试代码中未触发json_schema

测试中使用PydanticClassWithExternalClassMember(**d)时,字典d被当作Python关键字参数传入,Pydantic会将其视为Python对象场景,走python_schema逻辑。同时你的python_schema函数中已经包含了处理字典的逻辑,所以即使传入字典也不会触发json_schema。

触发json_schema的示例

修改测试代码,使用model_validate_json()验证JSON字符串,即可触发json_schema:

import json
# 序列化得到JSON字符串
json_str = json.dumps(d)
# 用JSON字符串验证模型
m2 = PydanticClassWithExternalClassMember.model_validate_json(json_str)

此时输出会包含:

json_schema called

内容的提问来源于stack exchange,提问作者newandlost

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 06:08:14