我正在尝试将一些Python对象转储到YAML中。
当前,无论使用YAML库(pyyaml
,oyaml
还是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
转储嵌套对象,但是未添加元数据?
答案 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标签