无法从yaml创建一系列Python对象
我正在尝试在结构内实例化YAML的一系列Python对象。在结构之外,我可以轻松地执行此操作,但是似乎YAML基本装载机未能递归地搜索我对象的子节点。
import yaml
import ruamel.yaml
class Person:
def __init__(self, name: str = 'JohnDoe'):
self.name = name
@classmethod
def from_yaml(cls, constructor, node):
for m in constructor.construct_yaml_map(node):
pass
if 'Name' in m:
name = m['Name']
return cls(name=name)
def __repr__(self):
return f'Person(name={self.name})'
class Car:
def __init__(self):
self.passengers = []
def add_person(self, person: Person = None):
self.passengers.append(person)
@classmethod
def from_yaml(cls, constructor, node):
for m in constructor.construct_yaml_map(node):
pass
inst = cls()
if 'Driver' in m:
inst.passengers = [m['Driver']]+inst.passengers
if 'Passengers' in m:
foo = m['Passengers']
print(f'm[\'Passengers\'] = {foo}')
for person in m['Passengers']:
inst.add_person(person)
return inst
def __repr__(self):
return f'Car(passengers={self.passengers})'
if __name__ == "__main__":
yaml = ruamel.yaml.YAML(typ='safe')
yaml.register_class(Person)
yaml.register_class(Car)
data = yaml.load("""
- !Person &0
Name: 'Paul'
- !Person &1
Name: 'George'
- !Person &3
Name: 'John'
- !Car
Driver: *0
Passengers: [*1]
- !Car
Driver: *3
Passengers:
- !Person &4
Name: 'Ringo'
""")
print(f'data = {data}')
上面的代码在执行时将以下代码打印到控制台:
m['Passengers'] = []
m['Passengers'] = []
data = [Person(name=Paul), Person(name=George), Person(name=John), Car(passengers=[Person(name=Paul)]), Car(passengers=[Person(name=John)])]
我希望输出无论如何
m['Passengers'] = [Person(name=George)]
m['Passengers'] = [Person(name=Ringo)]
data = [Person(name=Paul), Person(name=George), Person(name=John), Car(passengers=[Person(name=Paul), Person(name=George)]), Car(passengers=[Person(name=John), Person(name=Ringo)])]
,即使有一系列字符串,键“乘客”的关联值始终在字典中[]。
我是否必须手动告诉构造函数首先在from_yaml函数中遍历节点的其余部分,还是yaml加载程序从底部递归工作?
I am trying to instantiate an array of python objects from YAML, inside a struct. Outside of a struct I am able to do this easily, but it seems that the YAML BaseLoader is failing to recursively search the sub nodes of my object.
import yaml
import ruamel.yaml
class Person:
def __init__(self, name: str = 'JohnDoe'):
self.name = name
@classmethod
def from_yaml(cls, constructor, node):
for m in constructor.construct_yaml_map(node):
pass
if 'Name' in m:
name = m['Name']
return cls(name=name)
def __repr__(self):
return f'Person(name={self.name})'
class Car:
def __init__(self):
self.passengers = []
def add_person(self, person: Person = None):
self.passengers.append(person)
@classmethod
def from_yaml(cls, constructor, node):
for m in constructor.construct_yaml_map(node):
pass
inst = cls()
if 'Driver' in m:
inst.passengers = [m['Driver']]+inst.passengers
if 'Passengers' in m:
foo = m['Passengers']
print(f'm[\'Passengers\'] = {foo}')
for person in m['Passengers']:
inst.add_person(person)
return inst
def __repr__(self):
return f'Car(passengers={self.passengers})'
if __name__ == "__main__":
yaml = ruamel.yaml.YAML(typ='safe')
yaml.register_class(Person)
yaml.register_class(Car)
data = yaml.load("""
- !Person &0
Name: 'Paul'
- !Person &1
Name: 'George'
- !Person &3
Name: 'John'
- !Car
Driver: *0
Passengers: [*1]
- !Car
Driver: *3
Passengers:
- !Person &4
Name: 'Ringo'
""")
print(f'data = {data}')
the above code prints the following to the console on execution:
m['Passengers'] = []
m['Passengers'] = []
data = [Person(name=Paul), Person(name=George), Person(name=John), Car(passengers=[Person(name=Paul)]), Car(passengers=[Person(name=John)])]
where as I would expect the output to be
m['Passengers'] = [Person(name=George)]
m['Passengers'] = [Person(name=Ringo)]
data = [Person(name=Paul), Person(name=George), Person(name=John), Car(passengers=[Person(name=Paul), Person(name=George)]), Car(passengers=[Person(name=John), Person(name=Ringo)])]
no matter what, even with an array of strings, the associated value of the key 'Passengers' is always [] in the dictionary m.
do I have to manually tell the constructor to travers the rest of the node first in the from_yaml function, or does YAML loader work recursively from the bottom up?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
在您的示例中,无需
导入yaml
。在汽车建造过程中,其乘客尚不知道。所以
您需要做的是构建潜在的递归数据
作为
Person
和CAR
在两个步骤过程中,首先构建并产生“空”car
然后在已经产生的实例上填写
驱动程序
和任何passangers
。装载机知道如何处理此操作,因此您不必在
from_yaml
中反复出现。此外,您需要调用
constructor.construct_mapping(node,deep = true)
在
from_yaml
中,而不是您通过structionor.conscruct_yaml_map(node)
:whove:disv:
whit the the标签跟随锚,它更合适,但它更合适,但它更合适写锚
其次是标签,因为您将获得标记对象的锚定实例。
因此,这让我想知道
& 2!person>的名称是什么(可能与
!person& 2
相同),是Pete吗?There is no need to
import yaml
in your example.During the construction of the car, its passengers are not yet know. So
what you need to do is construct potentially recursive data such
as
Person
andCar
in a two step process, first constructing and yielding the "empty"Car
then filling in the
Driver
and anyPassangers
on the already yielded instance. The loader knowshow to handle this, so you don't have to recurse into anything in your
from_yaml
.Additionally you'll need to call
constructor.construct_mapping(node, deep=True)
in
from_yaml
, instead of your iteration overconstructor.construct_yaml_map(node)
:which gives:
Although it is allowed to write the tag followed by the anchor, it is IMO more appropriate to write the anchor
followed by the tag, because you'll get an anchored instance of the tagged object.
So that leaves me wondering what the name is of
&2 !Person
(probably the same as for!Person &2
), is it Pete?我能够在中找到部分答案。 /a>。
在
raumel.yaml
的情况下,看来我们的构造函数是from_yaml
函数,在注册课时会添加。我们要做的就是在from_yaml
初始化课程之后添加产量,然后在我们检索递归项目乘客
之前。I was able to find a partial answer in this post.
In the case of
raumel.yaml
, it looks like our constructor is thefrom_yaml
function, which gets added when the class is registered. All we have to do is add a yield after the initialization of our class infrom_yaml
, and before we retrieve our recursive itemPassengers
.