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

如何基于Pydantic动态生成类以反序列化Rust风格枚举

实现Pydantic版Rust风格标记联合

实现思路

利用Pydantic的__init_subclass__动态生成适配字段,结合全局字段验证器强制“仅能设置一个变体”的约束,让子类只需定义嵌套的BaseModel变体,即可自动适配Rust枚举的序列化格式。

完整实现代码

from pydantic import BaseModel, field_validator, ValidationError
from typing import Optional, Type

class RustEnum(BaseModel):
    @classmethod
    def __init_subclass__(cls):
        super().__init_subclass__()
        # 收集子类中定义的所有BaseModel类型变体
        variants = {}
        for name, attr in list(cls.__annotations__.items()):
            # 处理Optional包裹的变体类型
            if getattr(attr, '__origin__', None) is Optional:
                attr = attr.__args__[0]
            if isinstance(attr, Type) and issubclass(attr, BaseModel):
                variants[name] = attr
                # 移除原大写命名的注解,避免字段冲突
                del cls.__annotations__[name]
        
        # 动态添加小写命名的可选字段(对应Rust序列化的键名)
        for variant_name, variant_model in variants.items():
            field_name = variant_name.lower()
            cls.__annotations__[field_name] = Optional[variant_model]
            setattr(cls, field_name, None)
    
    @field_validator('*', mode='after')
    def enforce_single_variant(cls, values):
        # 统计已设置的变体数量
        active_variants = [key for key, value in values.items() if value is not None]
        if len(active_variants) != 1:
            raise ValueError(f"必须且仅能设置一个变体,当前已设置{len(active_variants)}个:{active_variants}")
        return values

使用示例

定义变体与枚举类

# 对应Rust枚举的变体模型
class Foo(BaseModel):
    a: int

class Bar(BaseModel):
    b: str

# 继承RustEnum创建枚举类
class FooBar(RustEnum):
    Foo: Foo
    Bar: Bar

验证正确场景

# 实例化Foo变体
foo_obj = FooBar(foo={"a": 123})
print(foo_obj.model_dump())
# 输出: {'foo': {'a': 123}}

# 实例化Bar变体
bar_obj = FooBar(bar={"b": "hello"})
print(bar_obj.model_dump())
# 输出: {'bar': {'b': 'hello'}}

验证错误场景

# 同时设置多个变体,触发验证错误
try:
    FooBar(foo={"a": 123}, bar={"b": "hello"})
except ValidationError as e:
    print(e.errors()[0]['msg'])
# 输出: 必须且仅能设置一个变体,当前已设置2个:['foo', 'bar']

# 未设置任何变体,触发验证错误
try:
    FooBar()
except ValidationError as e:
    print(e.errors()[0]['msg'])
# 输出: 必须且仅能设置一个变体,当前已设置0个:[]

关键细节说明

  • __init_subclass__:在子类继承时自动扫描BaseModel类型的变体定义,将大写变体名转换为小写可选字段,完美匹配Rust枚举的序列化键名格式。
  • 全局字段验证器:通过field_validator('*', mode='after')在所有字段验证完成后,检查变体设置数量,严格保证“仅一个变体”的约束。
  • 低侵入式定义:子类只需声明变体模型,无需额外编写字段或验证逻辑,批量创建枚举类时效率极高。

内容的提问来源于stack exchange,提问作者JP-Ellis

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.12 11:27:14