2011-12-28 15 views
13

¿Cómo se controla cómo el orden en el que PyYaml genera los pares de clave/valor al serializar un diccionario de Python?Controlar el orden de serialización de Yaml en Python

Estoy usando Yaml como un formato de serialización simple en una secuencia de comandos de Python. Mis objetos serializados de Yaml representan una especie de "documento", por lo que para una máxima facilidad de uso, me gustaría que el campo "nombre" de mi objeto aparezca primero en el archivo. Por supuesto, dado que el valor devuelto por el objeto __getstate__ es un diccionario y los diccionarios de Python están desordenados, el campo "nombre" se serializará en una ubicación aleatoria en la salida.

p. Ej.

>>> 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

Para el registro, hay una pregunta similar (pidió un par de años después de éste) aquí: http://stackoverflow.com/q/16782112/877069 –

Respuesta

15

Me tomó un par de horas de excavar a través de documentos y boletos PyYAML, pero finalmente descubrieron this comment que establece un código de prueba de concepto para la serialización de un OrderedDict como un mapa normal YAML (pero manteniendo el orden) .

p. Ej. aplicado a mi código original, la solución se ve algo como:

>>> 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

La última vez que revisé, los diccionarios de Python no estaban ordenados. Si realmente quieres que lo sean, te recomiendo usar una lista de pares clave/valor.

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

O bien, defina una lista con las teclas y colóquelas en el orden correcto.

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

Al igual que mi publicación dice, sé que los diccionarios de Python están desordenados. Desafortunadamente, hay una gran diferencia en la legibilidad de Yaml entre un diccionario y una lista de tuplas, por lo que esto no funcionará en mi caso. – Cerin

Cuestiones relacionadas