2011-12-28 110 views
13

如何控制PyYaml在序列化Python字典时如何输出键/值对的顺序?控制Python中的Yaml序列化顺序

我在Python脚本中使用Yaml作为简单的序列化格式。我的Yaml序列化对象代表一种“文档”,所以为了最大限度地方便用户,我希望我的对象的“名称”字段首先出现在文件中。当然,由于我的对象__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 
+0

为了记录在案,有一个类似的问题(问这个后一两年),在这里:http://stackoverflow.com/q/16782112/877069 – 2015-05-22 02:41:50

回答

15

,他带我穿过PyYAML文档和门票挖了几个小时,但我最终发现this comment,规定了证据的概念有些代码序列化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 
-7

上次我查了一下,Python的字典没有订购。如果你真的想要它们,我强烈建议使用键/值对列表。

[ 
    ('key', 'value'), 
    ('key2', 'value2') 
] 

或者,用键定义一个列表并将它们按正确的顺序排列。

keys = ['key1', 'name', 'price', 'key2']; 
for key in keys: 
    print obj[key] 
+4

就像我的帖子所说,我知道Python字典是无序的。不幸的是,在字典和元组列表之间的Yaml可读性存在很大差异,所以这对我来说不起作用。 – Cerin 2011-12-28 02:28:19