YAML-转储没有类型/标签的嵌套对象

时间:2019-04-24 09:18:38

标签: python yaml pyyaml ruamel.yaml

我正在尝试将一些Python对象转储到YAML中。

当前,无论使用YAML库(pyyamloyaml还是ruamel),我都遇到了一个问题,即调用.dump(MyObject)给我正确的YAML,但似乎以看起来像这样的形式添加有关我不需要的Python对象的大量元数据:

!!python/object:MyObject和其他类似的字符串。

我不需要能够从YAML重建对象,因此可以完全删除此元数据

关于SO的其他问题表明,对此的常见解决方案是使用safe_dump而不是dump

但是,safe_dump似乎不适用于嵌套对象(或根本没有对象),因为它会引发以下错误:

yaml.representer.RepresenterError: ('cannot represent an object', MyObject)

我看到这里的常见解决方法是为我要转储的对象手动指定Representers。我的问题是我的对象是我无法控制的生成代码。我还将转储各种不同的对象。

底线:是否可以使用.dump转储嵌套对象,但是未添加元数据?

2 个答案:

答案 0 :(得分:3)

尽管“正确的YAML”一词并不是很准确,但最好将其表述为 “ YAML输出看起来像您想要的,除了标记信息”,这幸运地提供了一些信息 有关您希望YAML外观的信息,因为有无数种转储对象的方式。

如果您使用{ "_id" : ObjectId("5cc03291528b226405341852"), "course" : ObjectId("5cbda8a7a2e03c23f674a2bd"), "__v" : 0, "schedule" : [ { "_id" : ObjectId("5cc03629a6b58e1f2ff05aae"), "subject" : ObjectId("5c9f42f8f4dd4f31d75648a0"), "date" : ISODate("2019-04-01T18:30:00.000Z"), "session" : "FN" }, { "_id" : ObjectId("5cc03629a6b58e1f2ff05aad"), "subject" : ObjectId("5c9f430bf4dd4f31d75648a1"), "date" : ISODate("2019-04-02T18:30:00.000Z"), "session" : "FN" }, { "_id" : ObjectId("5cc03629a6b58e1f2ff05aac"), "subject" : ObjectId("5c9f4324f4dd4f31d75648a2"), "date" : ISODate("2019-04-24T18:30:00.000Z"), "session" : "FN" }, { "_id" : ObjectId("5cc03629a6b58e1f2ff05aab"), "subject" : ObjectId("5c9f4331f4dd4f31d75648a3"), "date" : ISODate("2019-04-25T18:30:00.000Z"), "session" : "FN" }, { "_id" : ObjectId("5cc03629a6b58e1f2ff05aaa"), "subject" : ObjectId("5c9f4343f4dd4f31d75648a4"), "date" : ISODate("2019-04-17T18:30:00.000Z"), "session" : "FN" } ] } 转储对象:

ruamel.yaml

这给出了:

import sys
import ruamel.yaml

class MyObject:
   def __init__(self, a, b):
      self.a = a
      self.b = b
      self.c = [a, b]

data = dict(x=MyObject(42, -1))


yaml = ruamel.yaml.YAML(typ='unsafe')
yaml.dump(data, sys.stdout)

您有一个标签x: !!python/object:__main__.MyObject a: 42 b: -1 c: [42, -1] (您的位置可能会有所不同,具体取决于 类已定义等),并且该类的每个属性都作为映射的键转储。

关于清除转储中标记的方法有多种:

注册课程

向您的每个班级添加一个名为!!python/object:__main__.MyObject的{​​{1}}, 注册这些课程。您必须为每个课程都这样做, 但是这样做可以使您使用安全自卸车。有关如何 可以在 documentation

后处理

对输出进行后处理并删除标记是相当容易的,对于对象来说,标记总是在线上出现 您可以从classmethod中删除,直到行尾

to_yaml()

这给出了:

!!python

当标记被丢弃时,“从def strip_python_tags(s): result = [] for line in s.splitlines(): idx = line.find("!!python/") if idx > -1: line = line[:idx] result.append(line) return '\n'.join(result) yaml.encoding = None yaml.dump(data, sys.stdout, transform=strip_python_tags) 剥离 直到行尾”,当您转储具有 多个引用。

更换自卸车

您还可以更改不安全的转储程序,以映射到 识别用于对象的标签,并将标签更改为“普通” 一个用于字典/映射(通常不输出标签)

x: 
  a: 42
  b: -1
  c: [42, -1]

并再次给出:

!!python

这后两种方法无需定义即可适用于您定义的所有Python类的所有实例。

答案 1 :(得分:1)

速度快且容易破解

"\n".join([re.sub(r" ?!!python/.*$", "", l) for l in yaml.dump(obj).splitlines()]

  • "\n".join(...) –将列表合并为字符串
  • yaml.dump(obj).splitlines() –创建Yaml行的列表
  • re.sub(r" ?!!python/.*$", "", l) –用空字符串替换所有yaml python标签