在嵌套 class 中使用抽象外部 class 的子classes

Use subclasses of abstract outer class in nested class

我想在 pydantic class 的嵌套配置 class 中使用抽象 class 的所有子class,如下所示:

def custom_json_loads(classes, ....):
    ##use classes here for json parsing

class Outer(BaseModel, abc.ABC):
    name = "test"
    class Config:
        json_loads = partial(custom_json_loads, Outer.__subclasses__)

这一切的目的是我知道我的 JSON 的 OuterClass 类型和 classes 的名称表示应该创建子 class 的哪个实例

例如我有 BlueOuter、RedOuter、GreenOuter,在 json 中会有 “外”:{ “名称”:“BlueOuter”, ....}

但我不想导入所有可能的子class变体,因为它们会随着时间的推移而进化

为什么不使用 discriminated union

import abc
from typing import Annotated, Literal, Union

from pydantic import BaseModel, Field


class Outer(BaseModel, abc.ABC):
    ...


class BlueOuter(Outer):
    name: Literal["BlueOuter"]


class RedOuter(Outer):
    name: Literal["RedOuter"]


class GreenOuter(Outer):
    name: Literal["GreenOuter"]


OuterUnion = Annotated[
    Union[BlueOuter, RedOuter, GreenOuter], Field(discriminator="name")
]


class Foo(BaseModel):
    outer: OuterUnion


print(Foo.parse_raw('{"outer": {"name": "BlueOuter"}}'))
print(Foo.parse_raw('{"outer": {"name": "RedOuter"}}'))
print(Foo.parse_raw('{"outer": {"name": "GreenOuter"}}'))

输出:

outer=BlueOuter(name='BlueOuter')
outer=RedOuter(name='RedOuter')
outer=GreenOuter(name='GreenOuter')

如果您担心在添加新的 Outer 子类时需要维护 OuterUnion,您可以进行单元测试来检查 OuterUnion 是否包含 Outer:

class OrangeOuter(Outer):
    name: Literal["OrangeOuter"]


outer_union_classes = OuterUnion.__args__[0].__args__
for subclass in Outer.__subclasses__():
    assert (
        subclass in outer_union_classes
    ), f"{subclass.__name__} must be a member of OuterUnion (classes: {[c.__name__ for c in outer_union_classes]}). Please add it."

输出:

AssertionError: OrangeOuter must be a member of OuterUnion (classes: ['BlueOuter', 'RedOuter', 'GreenOuter']). Please add it.