PYAML抛出表​​示错误

时间:2013-08-22 07:32:54

标签: python dictionary yaml representation pyyaml

我有这个嵌套的字典类,我的实例需要转储到YAML

class NestedDict(dict):
    """Implementation of perl's autovivification feature."""
    def __getitem__(self, item):
        try:
            return dict.__getitem__(self, item)
        except KeyError:
            value = self[item] = type(self)()
            return value

转储此词典时:

pyaml.dump(nesteddict)

我收到此错误(仅发布整个邮件对象的摘录):

  

“RepresenterError:无法表示对象:{'a1401':'ts755',   'ts64':{'topic':{'a1561':'过程控制'}},'a1450':'ts107',   'a1609':'ts341','a1400':'ts753',......

那么如何在YAML中巧妙地代表这一点呢?我读到PyYAML确实支持嵌套的递归结构。

1 个答案:

答案 0 :(得分:2)

YAML确实支持嵌套的递归结构:

import ruamel.yaml

data = [1, 3]
data.append(data)

print ruamel.yaml.dump(data)

会给你YAML一个锚(&id001)和一个引用(*id001):

&id001
- 1
- 3
- *id001

你的dict的简单派生词可以被转储,至少ruamel.yaml也没有问题¹:

import ruamel.yaml

class NestedDict(dict):
    """Implementation of perl's autovivification feature."""
    def __getitem__(self, item):
        try:
            return dict.__getitem__(self, item)
        except KeyError:
            value = self[item] = type(self)()
            return value

data = NestedDict(a=1, b=2)
data['c'] = data

print ruamel.yaml.dump(data)

这会给你:

&id001 !!python/object/new:__main__.NestedDict
dictitems:
  a: 1
  b: 2
  c: *id001

如果您需要更复杂的表示,例如过滤掉一些 dict值,你必须告诉ruamel.yaml如何表示你的对象。 要告诉它NestedDict有一个代表,你可以使它成为ruamel.yaml.YAMLObject的子类,提供一个类属性yaml_tag = "!NestedDict"并实现__repr__();或者你可以提供一个明确的代表。

后者是内部使用的,IMO稍微容易实现,因为您可以通过返回对象的字典表示(即顶级键值对)来捎带字典代码。

def nested_dict_representer(dumper, node):
    return dumper.represent_mapping("!NestedDict", xyz)

其中xyz是对象的某个键值对表示。

¹免责声明:我是该软件包的作者,这是PyYAML的增强版本。