简体   繁体   English

Python,yaml嵌套对象

[英]Python, yaml nested objects

I am trying to create a yaml format that allow me to create an object inside another object. 我正在尝试创建一个yaml格式,允许我在另一个对象内创建一个对象。 In this sample i am trying to create a State Machine object and at the same time populate it with some states and connections between them. 在这个示例中,我尝试创建一个State Machine对象,同时在它们之间填充一些状态和连接。

yaml.load("""
!statemachine {
     states: [
       !state { name: p1 },
       !state { name: p2 },
       !state { name: p3 },],
     connections:
      [!connection { 'pim' : [p1,p2]}]}
""")

!statemachine have a constructor that generates an object of type MyStateMachine !statemachine有一个构造函数,可以生成MyStateMachine类型的对象

!state have a constructor that generates an object of type MyState !state有一个构造函数,它生成一个MyState类型的对象

!connection have a constructor that should use object generated with name p1 and add a connection to it !connection有一个构造函数,它应该使用名称为p1的对象生成并添加一个连接

I have 2 problems here: 我这里有两个问题:

1 - The constructor for state is called after the statemachine is created and the states are not present inside it 1 - 在创建statemachine并且其中不存在状态之后调用state的构造函数

2 - Retrieve the object p1 and invoke the method add_connection over it. 2 - 检索对象p1并在其上调用方法add_connection。

Thanks in advance 提前致谢

lets try the true pyyaml syntax for objects 让我们尝试对象的真正pyyaml语法

myyaml.py: myyaml.py:

import yaml,sys

class StateMachine(object):
    pass

class State(object):
    pass

class Connection(object):
    pass

if __name__ == '__main__':
    o = yaml.load("""
    !!python/object:myyaml.StateMachine {
         states: [
           !!python/object:myyaml.State { name: p1 },
           !!python/object:myyaml.State { name: p2 },
           !!python/object:myyaml.State { name: p3 },],
         connections:
          [       !!python/object:myyaml.Connection { 'pim' : [p1,p2]}]}
    """)
    print o.states[0].name
    print o.states[1].name
    print o.connections[0].pim
    sys.exit(0)

Gets: 获取:

p1
p2
['p1', 'p2']

And never try the yaml.load() in module's root block, always use if __name__ == '__main__' or call it within a function that you ensure it will be called once. 永远不要尝试模块的根块中的yaml.load(),总是使用if __name__ == '__main__'或在一个函数中调用它,确保它将被调用一次。

please note that yaml statement: 请注意yaml声明:

!!python/object:myyaml.State { name: p1 },

At this point yaml tries to import the myyaml.py again, in another context, and the all codes in the module's root will be executed, if you put yaml.load or anything like this in module's root, you may meet an infinite loop, or an unexpected result . 此时yaml尝试再次导入myyaml.py,在另一个上下文中,并且将执行模块根目录中的所有代码,如果你在模块的根目录中放入yaml.load或类似的东西,你可能遇到无限循环,或意外的结果。

To complement pylover's answer : if at some point you need more control on the serialization/deserialization process, try yamlable . 补充pylover的答案 :如果在某些时候你需要更多控制序列化/反序列化过程,请尝试yamlable I wrote this package for some of our production code, so as to gain a bit more control on the yaml-to-object binding. 我为我们的一些生产代码编写了这个包,以便对yaml-to-object绑定进行更多控制。

In your example: 在你的例子中:

import yaml
import sys
from yamlable import YamlAble, yaml_info


@yaml_info(yaml_tag_ns='myyaml')
class StateMachine(YamlAble):

    def __init__(self, states, connections):
        self.states = states
        self.connections = connections

    # def to_yaml_dict(self):
    #     return vars(self)
    #
    # @classmethod
    # def from_yaml_dict(cls, dct, yaml_tag):
    #     return StateMachine(**dct)


@yaml_info(yaml_tag_ns='myyaml')
class State(YamlAble):

    def __init__(self, name):
        self.name = name

    # def to_yaml_dict(self):
    #     return vars(self)
    #
    # @classmethod
    # def from_yaml_dict(cls, dct, yaml_tag):
    #     return State(**dct)


@yaml_info(yaml_tag_ns='myyaml')
class Connection(YamlAble):

    def __init__(self, pim):
        self.pim = pim

    # def to_yaml_dict(self):
    #     return vars(self)
    #
    # @classmethod
    # def from_yaml_dict(cls, dct, yaml_tag):
    #     return Connection(**dct)


if __name__ == '__main__':
    o = yaml.safe_load("""
    !yamlable/myyaml.StateMachine {
         states: [
           !yamlable/myyaml.State { name: p1 },
           !yamlable/myyaml.State { name: p2 },
           !yamlable/myyaml.State { name: p3 },],
         connections:
          [       !yamlable/myyaml.Connection { 'pim' : [p1,p2]}]}
    """)
    print(o.states[0].name)
    print(o.states[1].name)
    print(o.connections[0].pim)

    print(yaml.safe_dump(o))

    # Note: these also work
    # print(o.loads_yaml(""" ... """))
    # print(o.dumps_yaml())

    sys.exit(0)

If you need to change the default behaviour, for example to only dump some of the fields, or to change their structure for dumping, or to perform some custom instance creation at loading, uncomment the appropriate methods. 如果需要更改默认行为(例如,仅转储某些字段,或更改其转储结构),或者在加载时执行某些自定义实例创建,请取消注释相应的方法。

For more details, see yamlable documentation 有关更多详细信息,请参阅yamlable文档

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM