Python,yaml嵌套对象

时间:2013-06-19 09:57:24

标签: python deserialization yaml pyyaml

我正在尝试创建一个yaml格式,允许我在另一个对象中创建一个对象。 在此示例中,我尝试创建一个State Machine对象,同时在它们之间填充一些状态和连接。

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

!statemachine有一个构造函数,用于生成MyStateMachine

类型的对象

!state有一个构造函数,它生成一个MyState类型的对象

!connection有一个构造函数,它应该使用名称为p1的对象生成并添加一个连接

我有两个问题:

1 - 在创建 statemachine 并且其中没有状态后调用 state 的构造函数

2 - 检索对象p1并在其上调用方法add_connection。

提前致谢

2 个答案:

答案 0 :(得分:6)

让我们尝试对象的真pyyaml语法

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)

获取:

p1
p2
['p1', 'p2']

永远不要在模块的根块中尝试yaml.load(),始终使用if __name__ == '__main__'或在确保调用一次的函数中调用它。

请注意yaml声明:

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

此时yaml尝试再次导入myyaml.py,在另一个上下文中,并且将执行模块根目录中的所有代码,如果你将yaml.load或类似的东西放在模块的根目录中,你可能会遇到无限循环或意外结果。

答案 1 :(得分:0)

要补充pylover's answer:如果在某个时候您需要对序列化/反序列化过程进行更多控制,请尝试yamlable。我为我们的一些生产代码编写了此程序包,以便对yaml到对象的绑定获得更多控制。

在您的示例中:

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)

如果您需要更改默认行为,例如仅转储某些字段,或更改其结构以进行转储,或在加载时执行一些自定义实例创建,请取消注释相应的方法。

有关更多详细信息,请参见yamlable documentation