下面的代码尝试将C
的实例序列化为dict,然后再次反序列化回C
。由于data
的类型信息在dict()
的序列化过程中丢失,data
实例被解释为A
的实例,而不是B
(我的期望)。
我希望c_again
和c
相互匹配。我该怎么做呢?
from typing import Tuple, List
from pydantic import BaseModel
class A(BaseModel):
a: int
class B(A):
b: float
class C(BaseModel):
data: A
b = B(a=1, b=0.2)
c = C(data=b)
c_again = C(**c.dict())
print(c, ", ", c_again)
assert c == c_again
输出data=B(a=1, b=0.2) , data=A(a=1)
Traceback (most recent call last):
File "/home/h-ishida/tmp/tmp.py", line 18, in <module>
assert c == c_again
AssertionError
基于@bc291的评论:
作为起点,您需要将data
类型提示为几种可能类型的Union
,在您的示例中是data: Union[A, B]
。但这还不够:如果您只这样做,pydantic将尝试将您的数据匹配到它可以完成的第一个类型,因此它仍然将c_again.data
实例化为A(a=1)
,忽略b
键/属性。您可以通过在联合中首先提示B
来解决这个问题,就像Union[B, A]
一样,这是可行的,但它既不优雅也不健壮,特别是如果您的实际用例涉及许多子类,如您所说。
因此,您还需要将Config
添加到A
,这将使pydantic在b
存在时拒绝实例化它,因此它将跳过它并实例化一个匹配所有键/属性的Union
类(在本例中为B
)。注意,A的子类将继承此行为。
from typing import Union
from pydantic import BaseModel
class A(BaseModel):
a: int
class Config:
extra = 'forbid'
class B(A):
b: float
class C(BaseModel):
data: Union[A, B]
b = B(a=1, b=0.2)
c = C(data=b)
c_again = C(**c.dict())
print(c, ", ", c_again)
assert c == c_again
输出:
data=B(a=1, b=0.2) , data=B(a=1, b=0.2)
# no assertion error