Управление порядком сериализации Yaml в Python - PullRequest
13 голосов
/ 28 декабря 2011

Как вы управляете тем, как порядок, в котором PyYaml выводит пары ключ / значение при сериализации словаря Python?

Я использую Yaml как простой формат сериализации в скрипте Python. Мои сериализованные объекты Yaml представляют собой своего рода «документ», поэтому для максимальной простоты использования я бы хотел, чтобы поле «имя» моего объекта появилось первым в файле. Конечно, поскольку значение, возвращаемое __getstate__ моего объекта, является словарем, а словари Python неупорядочены, поле «имя» будет сериализовано в случайное место в выводе.

, например

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

Ответы [ 3 ]

18 голосов
/ 29 декабря 2011

Мне потребовалось несколько часов, чтобы покопаться в документах и ​​билетах 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
0 голосов
/ 02 декабря 2018

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
0 голосов
/ 28 декабря 2011

В последний раз, когда я проверял, словари Python не заказывались.Если вы действительно этого хотите, я настоятельно рекомендую использовать список пар ключ / значение.

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

В качестве альтернативы, определите список с ключами и расположите их в правильном порядке.

keys = ['key1', 'name', 'price', 'key2'];
for key in keys:
    print obj[key]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...