你得到null是因为dump()使用了Representer(),它是SafeRepresenter()的子类并代表None,调用了以下方法:
def represent_none(self, data):
return self.represent_scalar(u'tag:yaml.org,2002:null',
u'null')
由于字符串null 是硬编码的,因此dump() 无法更改它。
在 PyYAML 中解决此问题的正确方法是创建自己的 Dumper 子类,它具有 dump() 使用的标准 Dumper 中的 Emitter、Serializer 和 Resolver,但带有子类Representer 代表 None 您想要的方式:
import sys
import yaml
from yaml.representer import Representer
from yaml.dumper import Dumper
from yaml.emitter import Emitter
from yaml.serializer import Serializer
from yaml.resolver import Resolver
yaml_str = """\
attrs:
first:
second: value2
"""
class MyRepresenter(Representer):
def represent_none(self, data):
return self.represent_scalar(u'tag:yaml.org,2002:null',
u'')
class MyDumper(Emitter, Serializer, MyRepresenter, Resolver):
def __init__(self, stream,
default_style=None, default_flow_style=None,
canonical=None, indent=None, width=None,
allow_unicode=None, line_break=None,
encoding=None, explicit_start=None, explicit_end=None,
version=None, tags=None):
Emitter.__init__(self, stream, canonical=canonical,
indent=indent, width=width,
allow_unicode=allow_unicode, line_break=line_break)
Serializer.__init__(self, encoding=encoding,
explicit_start=explicit_start, explicit_end=explicit_end,
version=version, tags=tags)
MyRepresenter.__init__(self, default_style=default_style,
default_flow_style=default_flow_style)
Resolver.__init__(self)
MyRepresenter.add_representer(type(None),
MyRepresenter.represent_none)
data = yaml.load(yaml_str)
yaml.dump(data, stream=sys.stdout, Dumper=MyDumper, default_flow_style=False)
给你:
attrs:
first:
second: value2
如果仅仅为了摆脱 null 而这听起来像是很多开销,那就是。您可以采取一些捷径,甚至可以尝试将替代函数移植到现有的Representer,但由于实际使用的函数在查找表(由add_representer 填充)中引用,您至少需要处理参考。
更简单的解决方案是将 PyYAML 替换为 ruamel.yaml 并使用它的往返功能(免责声明:我是该软件包的作者):
import ruamel.yaml
yaml_str = """\
# trying to round-trip preserve empty scalar
attrs:
first:
second: value2
"""
data = ruamel.yaml.round_trip_load(yaml_str)
assert ruamel.yaml.round_trip_dump(data) == yaml_str
除了将None 作为空标量发出之外,它还保留了映射键、cmets 和标签名称的顺序,PyYAML 都没有。 ruamel.yaml 也遵循 YAML 1.2 规范(从 2009 年开始),其中 PyYAML 使用较旧的 YAML 1.1。
ruamel.yaml 软件包可以使用 PyPI 中的 pip 安装,也可以使用基于现代 Debian 的发行版安装,也可以使用 apt-get python-ruamel.yaml