让我首先说我想在pydantic
回购中打开一个问题。一旦我开始调试橡皮鸭,我得出的结论是,它实际上是pyyaml
不能正常工作,但我不确定了。
from dataclasses import dataclass
from functools import partial
from typing import List, Type
import yaml
from pydantic import BaseModel
yaml_input = """
!Foo
name: foo
bar:
- !Bar
name: bar
"""
def get_loader():
loader = yaml.SafeLoader
for tag_name, tag_constructor in tag_model_map.items():
loader.add_constructor(tag_name, tag_constructor)
return loader
def dynamic_constructor_mapping(model_class: Type[BaseModel], loader: yaml.SafeLoader,
node: yaml.nodes.MappingNode) -> BaseModel:
return model_class(**loader.construct_mapping(node))
def get_constructor_for_mapping(model_class: Type[BaseModel]):
return partial(dynamic_constructor_mapping, model_class)
class Bar(BaseModel):
name: str
class Foo1(BaseModel):
name: str
bar: list
class Foo2(BaseModel):
name: str
bar: List
class Foo3(BaseModel):
name: str
bar: List[Bar]
@dataclass
class Foo4:
name: str
bar: List[Bar]
foos = [Foo1, Foo2, Foo3, Foo4]
for foo_cls in foos:
tag_model_map = {
"!Foo": get_constructor_for_mapping(foo_cls),
"!Bar": get_constructor_for_mapping(Bar),
}
print(f"{foo_cls.__qualname__} loaded {yaml.load(yaml_input, Loader=get_loader())}")
打印
Foo1 loaded name='foo' bar=[Bar(name='bar')]
Foo2 loaded name='foo' bar=[]
Foo3 loaded name='foo' bar=[]
Foo4 loaded Foo4(name='foo', bar=[Bar(name='bar')])
- 如果在静态类型中使用
list
,则pydantic
对象列表解析正确 pydantic
对象列表NOT如果在静态类型 中使用pydantic
对象列表NOT如果在静态类型 中使用dataclass
对象列表总是被正确解析
List
,则正确解析List[Bar]
,则正确解析构造函数似乎在所有示例中返回正确的对象,所以我不明白问题出在哪里。
pydantic==1.8.2
Python 3.8.10
我和你有同样的问题。
为我解决这个问题的是在construct_mapping方法中将deep
设置为true。
的例子:
fields = loader.construct_mapping(node, deep=True)
所以这只是我在YAML中注意到的一个问题,但在我看来,将YAML反序列化为数据类的代码总体上比需要的更复杂。
如果您不需要pydantic
提供的数据验证功能,您还可以查看dataclass-wizard
,它提供了一个辅助YAMLWizard
Mixin类,可用于处理YAML数据——注意,这也依赖于pyyaml
库。
下面是一个简单的例子:
from __future__ import annotations
from dataclasses import dataclass
from dataclass_wizard import YAMLWizard
yaml_input = """
name: foo
bar:
- name: bar
"""
@dataclass
class Foo(YAMLWizard):
name: str
bar: list[Bar]
@dataclass
class Bar:
name: str
instance = Foo.from_yaml(yaml_input)
print(f'Loaded: {instance}')
安装dataclass-wizard
和pyyaml
,你可以包括yaml
额外:
pip install dataclass-wizard[yaml]