Me gustaría obtener el cargador de PyYAML para cargar asignaciones (y asignaciones ordenadas) en el tipo OrderedDict de Python 2.7+ , en lugar del vainilla dict
y la lista de pares que usa actualmente.
¿Cuál es la mejor manera de hacer eso?
fuente
Me gustaría obtener el cargador de PyYAML para cargar asignaciones (y asignaciones ordenadas) en el tipo OrderedDict de Python 2.7+ , en lugar del vainilla dict
y la lista de pares que usa actualmente.
¿Cuál es la mejor manera de hacer eso?
Actualización: en python 3.6+ probablemente no necesite OrderedDict
nada debido a la nueva implementación de dict que ha estado en uso en pypy durante algún tiempo (aunque se considera detalles de implementación de CPython por ahora).
Actualización: en python 3.7+, la naturaleza de preservación del orden de inserción de los objetos dict se ha declarado como una parte oficial de la especificación del lenguaje Python , consulte Novedades de Python 3.7 .
Me gusta la solución de @James por su simplicidad. Sin embargo, cambia la yaml.Loader
clase global predeterminada , lo que puede provocar efectos secundarios problemáticos. Especialmente, al escribir código de biblioteca, esta es una mala idea. Además, no funciona directamente con yaml.safe_load()
.
Afortunadamente, la solución se puede mejorar sin mucho esfuerzo:
import yaml
from collections import OrderedDict
def ordered_load(stream, Loader=yaml.Loader, object_pairs_hook=OrderedDict):
class OrderedLoader(Loader):
pass
def construct_mapping(loader, node):
loader.flatten_mapping(node)
return object_pairs_hook(loader.construct_pairs(node))
OrderedLoader.add_constructor(
yaml.resolver.BaseResolver.DEFAULT_MAPPING_TAG,
construct_mapping)
return yaml.load(stream, OrderedLoader)
# usage example:
ordered_load(stream, yaml.SafeLoader)
Para la serialización, no conozco una generalización obvia, pero al menos esto no debería tener ningún efecto secundario:
def ordered_dump(data, stream=None, Dumper=yaml.Dumper, **kwds):
class OrderedDumper(Dumper):
pass
def _dict_representer(dumper, data):
return dumper.represent_mapping(
yaml.resolver.BaseResolver.DEFAULT_MAPPING_TAG,
data.items())
OrderedDumper.add_representer(OrderedDict, _dict_representer)
return yaml.dump(data, stream, OrderedDumper, **kwds)
# usage:
ordered_dump(data, Dumper=yaml.SafeDumper)
El módulo yaml le permite especificar 'representantes' personalizados para convertir objetos de Python en texto y 'constructores' para revertir el proceso.
fuente
from six import iteritems
y luego cambiarlo paraiteritems(data)
que funcione igual de bien en Python 2 y 3.represent_dict
yDEFAULT_MAPPING_TAG
). ¿Esto se debe a que la documentación está incompleta o estas funciones no son compatibles y están sujetas a cambios sin previo aviso?dict_constructor
tendrá que llamarloader.flatten_mapping(node)
o no podrá cargar<<: *...
(combinar la sintaxis)Opción 2018:
oyaml
es un reemplazo directo para PyYAML que conserva el pedido de dict. Python 2 y Python 3 son compatibles. Solopip install oyaml
, e importe como se muestra a continuación:Ya no te molestarán las asignaciones arruinadas al descargar / cargar.
Nota: soy el autor de oyaml.
fuente
Opción 2015 (y posterior):
ruamel.yaml es una caída en el reemplazo de PyYAML (descargo de responsabilidad: soy el autor de ese paquete). Preservar el orden de las asignaciones fue una de las cosas que se agregaron en la primera versión (0.1) en 2015. No solo conserva el orden de los diccionarios, sino que también conserva los comentarios, los nombres de anclaje, las etiquetas y es compatible con YAML 1.2 especificación (lanzado en 2009)
La especificación dice que el orden no está garantizado, pero, por supuesto, hay un orden en el archivo YAML y el analizador apropiado puede retenerlo y generar de forma transparente un objeto que mantenga el orden. Solo tiene que elegir el analizador, el cargador y el volcador correctos¹:
Te regalaré:
data
es de tipoCommentedMap
que funciona como un dict, pero tiene información adicional que se mantiene hasta que se descarta (¡incluido el comentario conservado!)fuente
CommentedMap
directamente pero no funciona, y loOrderedDict
coloca en!!omap
todas partes, lo que no es muy fácil de usar.CommentedMap
consafe=True
inYAML
, que no funcionó (usandosafe=False
works). También tuve problemas paraCommentedMap
no ser modificable, pero no puedo reproducirlo ahora ... Abriré una nueva pregunta si encuentro este problema nuevamente.yaml = YAML()
, obtienes el analizador / volcador de ida y vuelta y eso es un derivado del analizador / volcador seguro que sabe sobre CommentedMap / Seq, etc.Nota : hay una biblioteca, basada en la siguiente respuesta, que implementa también CLoader y CDumpers: Phynix / yamlloader
Dudo mucho que esta sea la mejor manera de hacerlo, pero así es como se me ocurrió, y funciona. También disponible como una esencia .
fuente
key_node.start_mark
atributo en su mensaje de error, no veo ninguna forma obvia de simplificar su ciclo de construcción central. Si intenta utilizar el hecho de que elOrderedDict
constructor aceptará un iterable de pares clave, valor, perderá el acceso a ese detalle al generar el mensaje de error.add_constructor
su__init__
método.Actualización : la biblioteca quedó en desuso a favor del yamlloader (que se basa en el yamlordereddictloader)
Acabo de encontrar una biblioteca de Python ( https://pypi.python.org/pypi/yamlordereddictloader/0.1.1 ) que se creó en base a las respuestas a esta pregunta y es bastante simple de usar:
fuente
yodl
github.En mi instalación de For PyYaml para Python 2.7, actualicé __init__.py, constructor.py y loader.py. Ahora admite la opción object_pairs_hook para los comandos de carga. La diferencia de los cambios que hice está a continuación.
fuente
Aquí hay una solución simple que también busca claves duplicadas de nivel superior en su mapa.
fuente