python - parse - pyyaml install
¿Puede PyYAML volcar elementos de orden en orden no alfabético? (7)
Esto es realmente solo un addendum a la respuesta de @Blender. Si busca en la fuente PyYAML
, en el módulo representer.py
, encontrará este método:
def represent_mapping(self, tag, mapping, flow_style=None):
value = []
node = MappingNode(tag, value, flow_style=flow_style)
if self.alias_key is not None:
self.represented_objects[self.alias_key] = node
best_style = True
if hasattr(mapping, ''items''):
mapping = mapping.items()
mapping.sort()
for item_key, item_value in mapping:
node_key = self.represent_data(item_key)
node_value = self.represent_data(item_value)
if not (isinstance(node_key, ScalarNode) and not node_key.style):
best_style = False
if not (isinstance(node_value, ScalarNode) and not node_value.style):
best_style = False
value.append((node_key, node_value))
if flow_style is None:
if self.default_flow_style is not None:
node.flow_style = self.default_flow_style
else:
node.flow_style = best_style
return node
Si simplemente elimina la línea mapping.sort()
, entonces mantiene el orden de los elementos en el OrderedDict
.
Otra solución se da en este post . Es similar a @ Blender''s, pero funciona para safe_dump
. El elemento común es la conversión del dict a una lista de tuplas, por lo que la if hasattr(mapping, ''items'')
evalúa como falsa.
Actualizar:
Acabo de python2-yamlordereddictloader
cuenta de que el repositorio de EPEL del Proyecto Fedora tiene un paquete llamado python2-yamlordereddictloader
, y también hay uno para Python 3. El proyecto upstream para ese paquete es probablemente multiplataforma.
Estoy usando yaml.dump
para generar un dict. Imprime cada elemento en orden alfabético según la clave.
>>> d = {"z":0,"y":0,"x":0}
>>> yaml.dump( d, default_flow_style=False )
''x: 0/ny: 0/nz: 0/n''
¿Hay alguna forma de controlar el orden de los pares clave / valor?
En mi caso de uso particular, imprimir en reversa sería (casualmente) lo suficientemente bueno. Sin embargo, para completar, estoy buscando una respuesta que muestre cómo controlar el orden de manera más precisa.
He analizado el uso de collections.OrderedDict
pero PyYAML no (parece que) lo admite. También he buscado subclasificar yaml.Dumper
, pero no he podido averiguar si tiene la capacidad de cambiar el orden de los artículos.
Hay dos cosas que debes hacer para obtener esto como quieras:
- necesitas usar algo más que un
dict
, porque no mantiene los artículos ordenados - Necesitas deshacer esa alternativa de la manera apropiada.
import sys
import ruamel.yaml
from ruamel.yaml.comments import CommentedMap
d = CommentedMap()
d[''z''] = 0
d[''y''] = 0
d[''x''] = 0
ruamel.yaml.round_trip_dump(d, sys.stdout)
salida:
z: 0
y: 0
x: 0
¹ Esto se hizo usando ruamel.yaml un analizador de YAML 1.2, del cual soy el autor.
Para Python 3.7+, los dictados conservan el orden de inserción. Es mejor usar una biblioteca que respete eso, como oyaml :
>>> import oyaml as yaml # pip install oyaml
>>> d = {"z": 0, "y": 0, "x": 0}
>>> yaml.dump(d, default_flow_style=False)
''z: 0/ny: 0/nx: 0/n''
Probablemente haya una solución mejor, pero no pude encontrar nada en la documentación ni en la fuente.
Python 2 (ver comentarios)
OrderedDict
y le hice devolver una lista de elementos no almacenables:
from collections import OrderedDict
class UnsortableList(list):
def sort(self, *args, **kwargs):
pass
class UnsortableOrderedDict(OrderedDict):
def items(self, *args, **kwargs):
return UnsortableList(OrderedDict.items(self, *args, **kwargs))
yaml.add_representer(UnsortableOrderedDict, yaml.representer.SafeRepresenter.represent_dict)
Y parece funcionar:
>>> d = UnsortableOrderedDict([
... (''z'', 0),
... (''y'', 0),
... (''x'', 0)
... ])
>>> yaml.dump(d, default_flow_style=False)
''z: 0/ny: 0/nx: 0/n''
Python 3 o 2 (ver comentarios)
También puede escribir un representante personalizado, pero no sé si se encontrará con problemas más adelante, ya que eliminé un código de verificación de estilo:
import yaml
from collections import OrderedDict
def represent_ordereddict(dumper, data):
value = []
for item_key, item_value in data.items():
node_key = dumper.represent_data(item_key)
node_value = dumper.represent_data(item_value)
value.append((node_key, node_value))
return yaml.nodes.MappingNode(u''tag:yaml.org,2002:map'', value)
yaml.add_representer(OrderedDict, represent_ordereddict)
Pero con eso, puedes usar la clase nativa OrderedDict
.
Sobre la base de la respuesta de @orodbhen:
old_sorted = __builtins__[''sorted'']
__builtins__[''sorted''] = lambda x: x
with open(filename, ''w'') as outfile:
yaml.dump(f_json, outfile)
__builtins[''sorted''] = old_sorted
Simplemente reemplace la función incorporada ordenada por una función de identidad lambda mientras usa yaml.dump.
También estaba buscando una respuesta a la pregunta "¿cómo volcar asignaciones con el orden conservado?" No pude seguir la solución dada anteriormente, ya que soy nuevo en pyyaml y python. Después de dedicar algo de tiempo a la documentación de pyyaml y otros foros, encontré esto.
Puedes usar la etiqueta
!! omap
para volcar los mapeos conservando el orden. Si quieres jugar con el orden, creo que tienes que ir por las claves: valores
Los siguientes enlaces pueden ayudar a una mejor comprensión.
https://bitbucket.org/xi/pyyaml/issue/13/loading-and-then-dumping-an-omap-is-broken
Una sola línea para gobernarlos a todos:
yaml.add_representer(dict, lambda self, data: yaml.representer.SafeRepresenter.represent_dict(self, data.items()))
Eso es. Finalmente. Después de todos esos años y horas, el poderoso represent_dict
ha sido derrotado dándole el dict.items()
lugar de solo dict
Así es como funciona:
Este es el código fuente de PyYaml relevante:
if hasattr(mapping, ''items''):
mapping = list(mapping.items())
try:
mapping = sorted(mapping)
except TypeError:
pass
for item_key, item_value in mapping:
Para evitar la clasificación, solo necesitamos un objeto Iterable[Pair]
.items()
que no tenga .items()
.
dict_items
es un candidato perfecto para esto.
Aquí es cómo hacer esto sin afectar el estado global del módulo yaml:
#Using a custom Dumper class to prevent changing the global state
class CustomDumper(yaml.Dumper):
#Super neat hack to preserve the mapping key order. See https://.com/a/52621703/1497385
def represent_dict_preserve_order(self, data):
return self.represent_dict(data.items())
CustomDumper.add_representer(dict, CustomDumper.represent_dict_preserve_order)
return yaml.dump(component_dict, Dumper=CustomDumper)