在Python中控制Yaml序列化顺序

14 投票
4 回答
14934 浏览
提问于 2025-04-17 09:07

如何控制在使用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

撰写回答