Управление порядком Serialization Yaml в Python
Как вы контролируете, как порядок, в котором PyYaml выводит пары ключ/значение при сериализации словаря Python?
Я использую Yaml как простой формат сериализации в Python script. Мои сериализованные объекты Ямля представляют собой своего рода "документ", поэтому для максимального удобства пользователя я хотел бы, чтобы поле "имя" моего объекта появилось первым в файле. Конечно, поскольку значение, возвращаемое моим объектом __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
Ответы
Ответ 1
Мне потребовалось несколько часов, чтобы выкапывать документы и билеты PyYAML, но в итоге я обнаружил этот комментарий, в котором излагается код доказательной концепции для сериализации OrderedDict как нормальная карта ЯМЛ (но поддерживающая порядок).
например. применяется к моему исходному коду, решение выглядит примерно так:
>>> 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
Ответ 2
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
Ответ 3
В прошлый раз, когда я проверил, словари Python не были заказаны. Если вы действительно хотите, чтобы это было, я настоятельно рекомендую использовать список пар ключ/значение.
[
('key', 'value'),
('key2', 'value2')
]
В качестве альтернативы, определите список с помощью клавиш и поместите их в нужном порядке.
keys = ['key1', 'name', 'price', 'key2'];
for key in keys:
print obj[key]