在如此频繁地需要此功能后,我将这个答案(一个小包装器ruamel.yaml
)放入此处的 pip 模块中。
TLDR
pip install ez_yaml
import ez_yaml
ez_yaml.to_string(obj=your_object , options={})
ez_yaml.to_object(file_path=your_path, options={})
ez_yaml.to_object(string=your_string , options={})
ez_yaml.to_file(your_object, file_path=your_path)
原始问题的Hacky /复制粘贴解决方案
def object_to_yaml_str(obj, options=None):
#
# setup yaml part (customize this, probably move it outside this def)
#
import ruamel.yaml
yaml = ruamel.yaml.YAML()
yaml.version = (1, 2)
yaml.indent(mapping=3, sequence=2, offset=0)
yaml.allow_duplicate_keys = True
# show null
def my_represent_none(self, data):
return self.represent_scalar(u'tag:yaml.org,2002:null', u'null')
yaml.representer.add_representer(type(None), my_represent_none)
#
# the to-string part
#
if options == None: options = {}
from io import StringIO
string_stream = StringIO()
yaml.dump(obj, string_stream, **options)
output_str = string_stream.getvalue()
string_stream.close()
return output_str
原始答案(如果您想更多地自定义配置/选项)
import ruamel.yaml
from io import StringIO
from pathlib import Path
# setup loader (basically options)
yaml = ruamel.yaml.YAML()
yaml.version = (1, 2)
yaml.indent(mapping=3, sequence=2, offset=0)
yaml.allow_duplicate_keys = True
yaml.explicit_start = False
# show null
def my_represent_none(self, data):
return self.represent_scalar(u'tag:yaml.org,2002:null', u'null')
yaml.representer.add_representer(type(None), my_represent_none)
# o->s
def object_to_yaml_str(obj, options=None):
if options == None: options = {}
string_stream = StringIO()
yaml.dump(obj, string_stream, **options)
output_str = string_stream.getvalue()
string_stream.close()
return output_str
# s->o
def yaml_string_to_object(string, options=None):
if options == None: options = {}
return yaml.load(string, **options)
# f->o
def yaml_file_to_object(file_path, options=None):
if options == None: options = {}
as_path_object = Path(file_path)
return yaml.load(as_path_object, **options)
# o->f
def object_to_yaml_file(obj, file_path, options=None):
if options == None: options = {}
as_path_object = Path(Path(file_path))
with as_path_object.open('w') as output_file:
return yaml.dump(obj, output_file, **options)
#
# string examples
#
yaml_string = object_to_yaml_str({ (1,2): "hi" })
print("yaml string:", yaml_string)
obj = yaml_string_to_object(yaml_string)
print("obj from string:", obj)
#
# file examples
#
obj = yaml_file_to_object("./thingy.yaml")
print("obj from file:", obj)
object_to_yaml_file(obj, file_path="./thingy2.yaml")
print("saved that to a file")
咆哮
我感谢 Mike Night 解决了原来的“我只是希望它把输出返回给调用者”,并指出 Anthon 的帖子未能回答这个问题。我将进一步做:Anthon 你的模块很棒;往返令人印象深刻,是有史以来为数不多的旅行之一。但是,(这在 Stack Overflow 上经常发生)作者的工作不是让其他人的代码运行时高效。明确的权衡很好,作者应该帮助人们理解他们选择的后果。添加警告,包括名称中的“慢”等可能非常有帮助。但是,ruamel.yaml 文档中的方法;创建一个完整的继承类,不是“显式”的。它们是阻碍和混淆的,
许多用户理所当然地不关心运行时性能。我的程序的运行时间(没有 YAML)是 2 周。一个 500,000 行的 yaml 文件在几秒钟内被读取。2 周和几秒钟都与项目无关,因为它们是 CPU 时间,项目纯粹按工时计费。
由于正在对其执行其他操作,YAML 代码已经是一个字符串对象。将其强制转换为流实际上会导致更多开销。消除对 YAML 字符串形式的需求将涉及重写几个主要库并可能需要数月的努力;在这种情况下,使流成为非常不切实际的选择。
假设将其保留为流甚至是可能的,并且该项目按 CPU 时间而不是工时计费;优化 500,000 行的 yaml 文件作为字符串将提高 ≤0.0001% 的效率。花在找出这个问题的答案上的额外时间,以及其他人理解解决方法所花的时间,本可以花在提高其中一个每秒被调用 100 次的 c 函数的效率上。因此,即使我们确实关心 CPU 时间,特定方法仍然不是一个有用的选择。
忽略该问题同时还建议用户花费大量时间重写其应用程序的帖子不是答案。尊重他人,假设他们通常知道自己在做什么并且知道替代方案。然后,提供可能更有效的方法将得到赞赏而不是拒绝。
[结束吐槽]