在序列化Python字典时,如何控制PyYaml输出键/值对的顺序?
我在Python脚本中使用Yaml作为简单的序列化格式。我的Yaml序列化对象代表了一种“文档”,因此为了最大限度地方便用户,我希望我的对象的“名称”字段首先出现在文件中。当然,由于我的对象__getstate__
返回的值是字典,而Python字典是无序的,因此“name”字段将序列化为输出中的随机位置。
e.g。
>>> 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
答案 0 :(得分:17)
花了几个小时挖掘PyYAML文档和门票,但我最终发现this comment列出了一些概念验证代码,用于将OrderedDict序列化为普通的YAML映射(但保持顺序)
e.g。应用于我的原始代码,解决方案看起来像:
>>> 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
答案 1 :(得分:5)
我认为问题是当您转储数据时。
我查看了PyYaml的代码,然后有一个名为sort_keys
的可选参数,将该值设置为False
似乎可以解决问题。
答案 2 :(得分:2)
新解决方案(自 2020 和PyYAML 5.1起)
只需使用
,就可以按其当前顺序转储字典。yaml.dump(data, default_flow_style=False, sort_keys=False)
答案 3 :(得分:-1)
Cerin,非常感谢您的回答,它帮助我解决了我的问题。但是我花了一些时间来理解答案,因为没有提到输入字典。因此,我将使用输入字典重新发布@cerin的答案。在这里,输出显示为单独的条目。因此,此方法适用于以预定义的顺序将数据递归转储到yaml文件中。
import yaml
input_dict = {"first_key": "fist_value", "second_key": "second_value", "third_key": "third_value"}
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): # no need to preserve the order here
self.first_key = input_dict["first_key"]
self.second_key = input_dict["second_key"]
self.third_key = input_dict["third_key"]
def __getstate__(self): # this is where order should be defined
d = OrderedDict()
d['second_key'] = self.second_key
d['third_key'] = self.third_key
d['first_key'] = self.first_key
return d
dump_anydict_as_map(Document)
doc = Document('obj-20111227')
print(yaml.dump([doc], default_flow_style=False))
输出
- second_key: second_value
third_key: third_value
first_key: fist_value
答案 4 :(得分:-8)
我最后一次检查时,Python的字典没有被订购。如果您真的想要它们,我强烈建议使用键/值对列表。
[
('key', 'value'),
('key2', 'value2')
]
或者,使用键定义列表并按正确的顺序排列。
keys = ['key1', 'name', 'price', 'key2'];
for key in keys:
print obj[key]