Pydantic学习--BaseModel

部分源码

python 复制代码
class BaseModel(metaclass=_model_construction.ModelMetaclass):
    """!!! abstract "Usage Documentation"
        [Models](../concepts/models.md)

    A base class for creating Pydantic models.

    Attributes:
        __class_vars__: The names of the class variables defined on the model.
        __private_attributes__: Metadata about the private attributes of the model.
        __signature__: The synthesized `__init__` [`Signature`][inspect.Signature] of the model.

        __pydantic_complete__: Whether model building is completed, or if there are still undefined fields.
        __pydantic_core_schema__: The core schema of the model.
        __pydantic_custom_init__: Whether the model has a custom `__init__` function.
        __pydantic_decorators__: Metadata containing the decorators defined on the model.
            This replaces `Model.__validators__` and `Model.__root_validators__` from Pydantic V1.
        __pydantic_generic_metadata__: A dictionary containing metadata about generic Pydantic models.
            The `origin` and `args` items map to the [`__origin__`][genericalias.__origin__]
            and [`__args__`][genericalias.__args__] attributes of [generic aliases][types-genericalias],
            and the `parameter` item maps to the `__parameter__` attribute of generic classes.
        __pydantic_parent_namespace__: Parent namespace of the model, used for automatic rebuilding of models.
        __pydantic_post_init__: The name of the post-init method for the model, if defined.
        __pydantic_root_model__: Whether the model is a [`RootModel`][pydantic.root_model.RootModel].
        __pydantic_serializer__: The `pydantic-core` `SchemaSerializer` used to dump instances of the model.
        __pydantic_validator__: The `pydantic-core` `SchemaValidator` used to validate instances of the model.

        __pydantic_fields__: A dictionary of field names and their corresponding [`FieldInfo`][pydantic.fields.FieldInfo] objects.
        __pydantic_computed_fields__: A dictionary of computed field names and their corresponding [`ComputedFieldInfo`][pydantic.fields.ComputedFieldInfo] objects.

        __pydantic_extra__: A dictionary containing extra values, if [`extra`][pydantic.config.ConfigDict.extra]
            is set to `'allow'`.
        __pydantic_fields_set__: The names of fields explicitly set during instantiation.
        __pydantic_private__: Values of private attributes set on the model instance.
    """

	__pydantic_fields__: ClassVar[Dict[str, FieldInfo]]  # noqa: UP006
    """A dictionary of field names and their corresponding [`FieldInfo`][pydantic.fields.FieldInfo] objects.
    This replaces `Model.__fields__` from Pydantic V1.
    """

	__pydantic_extra__: Dict[str, Any] | None = _model_construction.NoInitField(init=False)  # noqa: UP006
    """A dictionary containing extra values, if [`extra`][pydantic.config.ConfigDict.extra] is set to `'allow'`."""

元类机制

AI回答: 与普通 Python 类不同,BaseModel 使用自定义元类 ModelMetaclass。当你的子类被定义时,元类会在解释器读取类体的那一刻,自动收集所有的类型注解(annotations ),并生成对应的核心数据结构(CoreSchema)。 这就是 Pydantic 性能强悍的第一个秘密:大量工作前置到类定义阶段完成,实例化时只需调用已编译好的 Rust 验证器

核心验证

python 复制代码
__pydantic_core_schema__: ClassVar[CoreSchema]
__pydantic_serializer__: ClassVar[SchemaSerializer] # SchemaValidator:负责实例化时的数据校验与强制转换。
__pydantic_validator__: ClassVar[SchemaValidator | PluggableSchemaValidator] # chemaSerializer:负责高速地序列化为 Python 字典或 JSON。

这是 V2 与 V1 最大的架构变化 。在 Pydantic V1 中,验证逻辑全由 Python 编写,速度较慢。V2 中,元类首先把你的模型声明编译成 CoreSchema,然后交给由 Rust 编写的 pydantic-core

字段与状态

  • __pydantic_fields__:存储了模型中所有字段的元信息(默认值、是否必填、别名等),由元类在定义阶段填充。
  • __pydantic_fields_set__至关重要 。它记录了实例化时你显式传递了哪些字段 。这能精确区分"未传值"与"主动传了 None",在处理 PATCH 操作或部分更新时极其有用。
  • __pydantic_extra__ :当模型配置了 extra='allow',所有未定义的额外字段会被安全收纳到这里,不至于丢失数据。

学习例子

基础

  1. 基础访问数据:
python 复制代码
from typing import *
from pydantic import BaseModel, ValidationError, ConfigDict, Field

class User(BaseModel):
    age: int
    name: 

try:
    user2 = User(age="10000", name="ak") # 不会报错,原因:Pydantic默认为宽松模式,内置类型强制转换,尽量转数据类型
    print(f"{type(user2.age)}")
except ValidationError as e:
    print(f"发生报错:{e}")
  1. 防止字段隐式转换:
python 复制代码
from pydantic import BaseModel, ValidationError, ConfigDict, Field

class User(BaseModel):
    model_config = ConfigDict(strict=True) # 所有字段开启严格校验

    age: int
    name: str

class User(BaseModel):
    age: int = Field(strict=True) # 指明这个字段拒绝隐式转换
    name: str
  1. 序列化与反序列化:
python 复制代码
# 序列化
dict_1 = user1.model_dump()
json_1 = user1.model_dump_json()

print(f"dict_1={dict_1} \n json_1={json_1}")
#dict_1={'age': 20, 'name': 'AK'}
# json_1={"age":20,"name":"AK"}

# 反序列化
new_User = User.model_validate_json(json_1)
print(new_User) # 打印输出:age=20 name='AK'
  1. 增加字段、查看原有字段
python 复制代码
class User(BaseModel):
    model_config = ConfigDict(extra="allow") # 允许增加字段

    age: int
    name: str

user1 = User(name="AK", age=20, color="blue")
print(f"显示传递:{user1.__pydantic_fields_set__} \t 未定义字段:{user1.__pydantic_extra__}") 
# 打印输出:显示传递:{'color', 'age', 'name'}         未定义字段:{'color': 'blue'}

进阶

  1. 增加字段复杂度,如嵌套数据
python 复制代码
class Item(BaseModel):
    name: str
    price: float

class Order(BaseModel):
    order_id: str
    items: List[Item]       # 包含多个Item对象的列表
    status: Tuple[str, str] # 元组:(订单状态, 配送状态)

order_data = {
    'order_id': "741239478921",
    'items': [
        {'name': "Laptop", 'price': 100.1},
        {'name': "Mouse", 'price': 49.9}
    ],
    'status': ("Paid", "Shipped")
}

order = Order(**order_data) # 通过字典,然后解包**,实例化对象
print(f"order= {order}")
  1. 模型继承,共享相同字段
python 复制代码
class Base1(BaseModel):
    a: str
    b: str
    c: str

class Test_Base1(Base1):
    price: int

te = Test_Base1(a="", b="", c="", price=10)
print(te) # a='' b='' c='' price=10
  1. 树形递归结构
python 复制代码
class Department(BaseModel):
    id: int
    name: str
    children: Optional[List['Department']] = None # 递归类型注解:子节点依然是 Department 对象的列表

# 传入嵌套字典,自动解析为树形对象
dept_data = {
    "id": 1, "name": "总公司", 
    "children": [
        {"id": 2, "name": "研发部", "children": None},
        {"id": 3, "name": "市场部", "children": [
            {"id": 4, "name": "华南区", "children": None}
        ]}
    ]
}

dept = Department(**dept_data)
print(dept)
# id=1 name='总公司' children=[Department(id=2, name='研发部', children=None), Department(id=3, name='市场部', children=[Department(id=4, name='华南区', children=None)])]
  1. 字段约束
python 复制代码
from typing import Annotated

class Product(BaseModel):
    name: str = Field(min_length=2, max_length=10)
    
    price: Annotated[float, Field(..., ge=0, description="产品价格")] 
    price2: float = Field(..., ge=0, description="产品价格")
  1. 自定义业务逻辑校验
python 复制代码
from pydantic import field_validator, model_validator


class Item(BaseModel):
    name: str
    price: float

class OrderInfo(BaseModel):
    user_email:str
    items: List[Item]
    total_amount: float

    # 验证字段user_email,确保邮箱含有字符@
    @field_validator('user_email')
    @classmethod
    def validate_email(cls, value:str) -> str:
        if '@' not in value:
            raise ValidationError("Email must contain "@" symbol")
        return value
    
    # 跨字段校验
    @model_validator(mode='after')
    def check_total_amout(self) -> 'OrderInfo':
        # 自定义策略
        if self.items and self.total_amount is not None:
            total_price = sum( item.price for item in self.items)
            if total_price > self.total_amount:
                raise ValueError('Total amount cannot be less than the sum of item prices.')
        return self

validate_email()函数的逻辑:实例化类OrderInfo时,仅对字段user_email进行校验。 必须使用 @classmethod,第一个参数是 cls(代表类本身),第二个参数 value 是传入的邮箱字符串。

check_total_amout()函数的逻辑:

  • 触发时机 :在所有字段(包括 user_emailitems)都完成基础校验和转换之后执行。
  • mode='after':这是 Pydantic V2 的语法,表示在所有字段解析完成后执行。
  • self 参数 :注意这里没有 @classmethod,它是一个实例方法。因为此时模型已经初步构建,你可以直接通过 self.itemsself.total_amount 访问已转换好的对象属性。
相关推荐
fu15935745681 小时前
【边缘计算实战】P1:从零搭建边云任务卸载仿真实验台(Python 可复现)
数据库·python·边缘计算
蜡台2 小时前
通过Gradle脚本声明更改Java变量
android·java·开发语言·python·kotlin·gradle·groovy
智能体与具身智能2 小时前
TVA 本质内涵与核心特征(系列)
人工智能·python·智能体视觉
云雾J视界3 小时前
SST:高频变压器设计实战:铁氧体 vs 纳米晶 vs 非晶,磁性材料怎么选
python·acdc·dab·sst
第一程序员3 小时前
Rust trait 入门:把 AI 客户端抽象成可替换接口
python·rust·github
Ulyanov3 小时前
Python实现6-DOF刚体仿真器(下)——环境扰动与控制闭环
开发语言·python·算法·系统仿真·雷达电子对抗·导引头
小小的木头人4 小时前
Python 批量解析 Excel 经纬度,调用高德地图 API 获取中文地址
开发语言·python·excel
金銀銅鐵4 小时前
[Python] 为 Vole 机器语言实现图形化界面
python·程序员
小林ixn4 小时前
Python基础全梳理:从注释到函数,这些细节你都掌握了吗?
python·编程语言