2011-12-28 16 views
13

Come si controlla l'ordine in cui PyYaml emette coppie chiave/valore durante la serializzazione di un dizionario Python?Controllo dell'ordine di serializzazione Yaml in Python

Sto usando Yaml come un semplice formato di serializzazione in uno script Python. Gli oggetti serializzati My Yaml rappresentano una sorta di "documento", quindi per la massima facilità d'uso, vorrei che il campo "nome" del mio oggetto appaia per primo nel file. Ovviamente, poiché il valore restituito dal mio oggetto __getstate__ è un dizionario e i dizionari Python non sono ordinati, il campo "nome" verrà serializzato in una posizione casuale nell'output.

ad es.

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

Per la cronaca, c'è una domanda simile (ha chiesto un paio di anni dopo questo) qui: http://stackoverflow.com/q/16782112/877069 –

risposta

15

ho messo un paio d'ore di scavare attraverso documenti PyYAML e biglietti, ma alla fine ho scoperto this comment che espone un codice proof-of-concept per la serializzazione di un OrderedDict come una mappa YAML normale (ma mantenendo l'ordine) .

ad es. applicata al mio codice originale, la soluzione sembra qualcosa di simile:

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

L'ultima volta che ho controllato, i dizionari Python non erano ordinati. Se vuoi davvero che siano, ti consiglio caldamente di usare un elenco di coppie chiave/valore.

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

In alternativa, definire un elenco con i tasti e inserirli nell'ordine corretto.

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

Come il mio post dice, so che i dizionari Python non sono ordinati. Sfortunatamente, c'è una grande differenza nella leggibilità di Yaml tra un dizionario e un elenco di tuple, quindi non funzionerà nel mio caso. – Cerin