【问题标题】:Direct instantiation of `typing.Union` in Python在 Python 中直接实例化 `typing.Union`
【发布时间】:2020-04-25 05:56:12
【问题描述】:

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

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

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

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

【问题讨论】:

  • 你不能实例化一个联合,这甚至没有意义。
  • 联合代表“A、B 或 C 中的一个”。看起来你想要“所有 A、B 和 C”,这不是一个联合。
  • 根据上面的cmets,Union是一个类型提示,告诉python一个变量应该是什么类型。它本身不是一个类。它并不代表将两种类型或类合并为一个新的组合类型/类。

标签: python typing pydantic


【解决方案1】:

Union 不是这样运作的。

Union 与 C 中的 union 相同。

表示变量可以是A型,也可以是B型。

例如

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

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

【讨论】:

  • 不,它与 C 中的 union 完全不同。
  • 是的。但是,如果你说我错了,你也应该说什么是错的……
  • C 中的联合是一个特定的东西,一块在任何给定时刻都可以被解释为一种或另一种的内存。 IE。 union foo {int x; float y}; 然后像union foo; foo.x = 4; 这样我可以做像printf( "%d\n", foo.x); printf("%d\n", foo.y) 这样的事情,也就是说,联合就像一个带有成员的结构,只是这些成员共享内存。 Python 没有这样的东西。虽然从类型论的角度来看,这可以被认为是一个 sum 类型,这就是 Python 中 Union 的含义,但这并不意味着 Python Unions 就像 C unions。
  • 在python中一切都是指针,所以指向联合的指针……
  • A C Union 是两个同时。 Python union 是一种类型注释,指示变量是或,但不能同时是两者
【解决方案2】:

看起来你想要的是一个工厂函数,它可以根据调用中提供的关键字参数猜测 ABC 中的哪一个来实例化。

例如:

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 都不期望的参数。

【讨论】:

  • 所有这些都可以通过我编写的这个typedload 模块来实现。类似于load(kwargs, Union[A, B, C]),但类也需要使用打字或属性才能被识别。
【解决方案3】:

你想要这种行为吗?

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)])

验证DC:https://github.com/EvgeniyBurdin/validated_dc

【讨论】:

    【解决方案4】:

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

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

    【讨论】:

      猜你喜欢
      • 2011-12-20
      • 2021-01-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多