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 dicty 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 dicty 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 OrderedDictnada 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.Loaderclase 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 iteritemsy luego cambiarlo paraiteritems(data)que funcione igual de bien en Python 2 y 3.represent_dictyDEFAULT_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_constructortendrá que llamarloader.flatten_mapping(node)o no podrá cargar<<: *...(combinar la sintaxis)Opción 2018:
oyamles 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é:
dataes de tipoCommentedMapque funciona como un dict, pero tiene información adicional que se mantiene hasta que se descarta (¡incluido el comentario conservado!)fuente
CommentedMapdirectamente pero no funciona, y loOrderedDictcoloca en!!omaptodas partes, lo que no es muy fácil de usar.CommentedMapconsafe=TrueinYAML, que no funcionó (usandosafe=Falseworks). También tuve problemas paraCommentedMapno 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_markatributo 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 elOrderedDictconstructor aceptará un iterable de pares clave, valor, perderá el acceso a ese detalle al generar el mensaje de error.add_constructorsu__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
yodlgithub.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