4

我想实例化两个直接派生的类的类型。Unionpydantic.BaseModel但是我得到一个TypeError: Cannot instantiate typing.Union.

我见过的所有示例都声明Union为类的属性(例如此处)。

下面是我想使用的最小示例。

from pydantic import BaseModel
from typing import Union

class A(BaseModel):
    a: int

class B(A):
    b: int

class C(A):
    c: str

MyUnion = Union[B, C, A]
mu = MyUnion(a=666, c='foo')  #  This command throws the TypeError

有没有办法做到这一点?

这是我得到的错误

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-40-8163e3490185> in <module>
----> 1 MyUnion()

c:\program files\python37\lib\typing.py in __call__(self, *args, **kwargs)
    668             raise TypeError(f"Type {self._name} cannot be instantiated; "
    669                             f"use {self._name.lower()}() instead")
--> 670         result = self.__origin__(*args, **kwargs)
    671         try:
    672             result.__orig_class__ = self

c:\program files\python37\lib\typing.py in __call__(self, *args, **kwds)
    327
    328     def __call__(self, *args, **kwds):
--> 329         raise TypeError(f"Cannot instantiate {self!r}")
    330
    331     def __instancecheck__(self, obj):

TypeError: Cannot instantiate typing.Union
4

5 回答 5

7

联盟不是这样运作的。

unionUnion 与C中的 the 相同。

这意味着变量可以是 A 类型或 B 类型。

例如

def f(a: Union[int, str]) -> None:
   ...

这意味着a可以是 anint或 a str,它们的子类,仅此而已。

于 2020-01-07T17:32:16.200 回答
2

我知道我没有与问题完全相同的问题,但是对于在这里登陆的其他人,我通过更改Union(int, blah)为解决了我的问题Union[int, blah]

重要的是我不小心使用了括号而不是方括号。:/

于 2021-12-28T03:23:39.140 回答
1

看起来您想要的是一个工厂函数,它根据调用中提供的关键字参数猜测AB或中的哪一个C进行实例化。

例如:

from pydantic import BaseModel
from typing import Union

class A(BaseModel):
    a: int

class B(A):
    b: int

class C(A):
    c: str

def a_b_or_c(**kwargs) -> Union[B, C, A]:
    if 'c' in kwargs:
        return C(**kwargs)
    elif 'b' in kwargs:
        return B(**kwargs)
    elif 'a' in kwargs:
        return A(**kwargs)
    else:
        raise Exception("I don't know what class you want")

my = a_b_or_c(a=666, c='foo')

a_b_or_c当然,可以对 中的参数进行更广泛的测试kwargs,例如防止传递ABC都不期望的参数。

于 2020-01-07T17:42:03.810 回答
1

您正在寻找的是parse_obj_as

https://pydantic-docs.helpmanual.io/usage/models/#parsing-data-into-a-specified-type

from pydantic import BaseModel, parse_obj_as
from typing import Union

class A(BaseModel):
    a: int

class B(A):
    b: int

class C(A):
    c: str

MyUnion = Union[B, C, A]
mu = parse_obj_as(MyUnion, {"a":666, "c":'foo'}) 
mu
# >>> C(a=666, c='foo')
于 2022-01-28T10:28:34.447 回答
0

你想要这种行为吗?

from dataclasses import dataclass
from typing import Union, List

from validated_dc import ValidatedDC


@dataclass
class I(ValidatedDC):
    i: int


@dataclass
class F(ValidatedDC):
    f: float


@dataclass
class S(ValidatedDC):
    s: str


@dataclass
class MyUnion(ValidatedDC):
    data: List[Union[I, F, S]]


my_union = MyUnion([{'i': 1}, {'s': 'S'}, {'f': 0.2}])
assert my_union.get_errors() is None
assert my_union == MyUnion(data=[I(i=1), S(s='S'), F(f=0.2)])

ValidatedDC:https ://github.com/EvgeniyBurdin/validated_dc

于 2020-05-26T17:09:34.980 回答