在过去,我使用与some_fancy_printing_loggin_func(yaml.dump(...), ...)
兼容的ruamel.yaml进行类似的操作,但是我希望将代码转换为使用最新的API,这样我就可以利用一些新的格式化设置。
但是,我讨厌我必须指定一个流到ruamel.yaml.YAML.dump()
.我不希望它直接写入流;我只希望它将输出返回给调用者。我遗漏了什么?
PS:我知道我可以做一些类似的事情,虽然我当然想避免这样做。
f = io.StringIO()
yml.dump(myobj, f)
f.seek(0)
my_logging_func(f.read())
发布于 2020-07-30 19:18:32
这个答案(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解决了原来的“我只想让它把输出返回给调用者”,并呼吁Anthon的帖子没有回答这个问题。我将做进一步的工作: Anthon,您的模块很棒;往返旅行是令人印象深刻的,也是为数不多的几个模块之一。但是,(这经常发生在堆栈溢出上)使其他人的代码运行时高效并不是作者的工作。明确的权衡是伟大的,作者应该帮助人们理解他们的选择的后果。添加警告,包括名称中的“慢速”等,可能会非常有用。但是,ruamel.yaml文档中的方法;创建整个继承的类,并不是“显式”的。它们是封闭和混淆的,使得其他人很难执行,也很难理解这些附加代码存在的原因和原因。
许多用户完全不关心运行时的性能。没有YAML的我的程序运行时间是2周。一个500,000行yaml文件在几秒钟内被读取。两个星期和几秒钟都与项目无关,因为它们是CPU时间,项目是纯人工时间计费的。
由于在YAML上执行其他操作,YAML代码已经是一个字符串对象。强迫它进入流实际上会造成更多的开销。消除对YAML字符串形式的需求需要重写几个主要库,并可能需要几个月的努力;在这种情况下,流是一个非常不切实际的选择。
假设将其保持为流甚至是可能的,并且该项目是按CPU时间而不是人工时间计费的;优化50万行yaml文件字符串将提高≤0.0001%的效率。找出这个问题的答案所花费的额外时间,以及其他人花在理解这项工作上的时间,本来可以花在提高c-函数的效率上,这种c-函数每秒被调用100次。因此,即使我们确实关心CPU时间,特定的方法仍然不能成为一个有用的选择。
一篇文章忽略了这个问题,同时也暗示用户可能会花费大量的时间重写他们的应用程序,但这并不是一个答案。尊重别人,假设他们通常知道自己在做什么,并且知道其他选择。然后,提供可能更有效的方法将受到赞赏,而不是被拒绝。
末端咆哮
https://stackoverflow.com/questions/47614862
复制相似问题