在Python中控制Yaml序列化顺序
如何控制在使用PyYaml将Python字典转成Yaml格式时,键值对输出的顺序?
我在一个Python脚本中使用Yaml作为简单的序列化格式。我的Yaml序列化对象代表一种“文档”,为了让用户更方便使用,我希望对象的“name”字段能在文件中最先出现。当然,由于我的对象的__getstate__
返回的是一个字典,而Python字典是无序的,所以“name”字段会被随机放在输出中的某个位置。
例如:
>>> import yaml
>>> class Document(object):
... def __init__(self, name):
... self.name = name
... self.otherstuff = 'blah'
... def __getstate__(self):
... return self.__dict__.copy()
...
>>> doc = Document('obj-20111227')
>>> print yaml.dump(doc, indent=4)
!!python/object:__main__.Document
otherstuff: blah
name: obj-20111227
4 个回答
6
我觉得问题出在你导出数据的时候。我查看了PyYaml的代码,发现有一个可选的参数叫做 sort_keys
,把这个值设置为 False
似乎就能解决这个问题。
21
新解决方案(截至2020年和PyYAML 5.1版本)
你可以通过简单地使用下面的代码,将一个字典按照它当前的顺序输出:
yaml.dump(data, default_flow_style=False, sort_keys=False)
20
我花了几个小时翻阅PyYAML的文档和问题,最终发现了这个评论,里面提供了一些示例代码,展示了如何将一个有序字典(OrderedDict)序列化成普通的YAML映射,同时保持顺序。
比如,应用到我最初的代码上,解决方案大概是这样的:
>>> import yaml
>>> from collections import OrderedDict
>>> def dump_anydict_as_map(anydict):
... yaml.add_representer(anydict, _represent_dictorder)
...
>>> def _represent_dictorder( self, data):
... if isinstance(data, Document):
... return self.represent_mapping('tag:yaml.org,2002:map', data.__getstate__().items())
... else:
... return self.represent_mapping('tag:yaml.org,2002:map', data.items())
...
>>> class Document(object):
... def __init__(self, name):
... self.name = name
... self.otherstuff = 'blah'
... def __getstate__(self):
... d = OrderedDict()
... d['name'] = self.name
... d['otherstuff'] = self.otherstuff
... return d
...
>>> dump_anydict_as_map(Document)
>>> doc = Document('obj-20111227')
>>> print yaml.dump(doc, indent=4)
!!python/object:__main__.Document
name: obj-20111227
otherstuff: blah