Ich möchte PyYAMLs Loader dazu bringen, Mappings (und geordnete Mappings) in den Python 2.7+ OrderedDict- Typ zu laden , anstelle der Vanille dict
und der Liste der Paare, die derzeit verwendet werden.
Was ist der beste Weg das zu tun?
quelle
Ich möchte PyYAMLs Loader dazu bringen, Mappings (und geordnete Mappings) in den Python 2.7+ OrderedDict- Typ zu laden , anstelle der Vanille dict
und der Liste der Paare, die derzeit verwendet werden.
Was ist der beste Weg das zu tun?
Update: In Python 3.6+ benötigen Sie wahrscheinlich OrderedDict
aufgrund der neuen Dikt-Implementierung , die seit einiger Zeit in Pypy verwendet wird, überhaupt nichts (obwohl dies vorerst als CPython-Implementierungsdetail betrachtet wird).
Update: In Python 3.7+ wurde die Beibehaltung der Einfügungsreihenfolge von diktierten Objekten als offizieller Bestandteil der Python-Sprachspezifikation deklariert (siehe Neue Funktionen in Python 3.7) .
Ich mag die Lösung von @James wegen ihrer Einfachheit. Es ändert jedoch die globale Standardklasse yaml.Loader
, was zu störenden Nebenwirkungen führen kann. Insbesondere beim Schreiben von Bibliothekscode ist dies eine schlechte Idee. Es funktioniert auch nicht direkt mit yaml.safe_load()
.
Glücklicherweise kann die Lösung ohne großen Aufwand verbessert werden:
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)
Für die Serialisierung kenne ich keine offensichtliche Verallgemeinerung, aber zumindest sollte dies keine Nebenwirkungen haben:
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)
Mit dem yaml-Modul können Sie benutzerdefinierte 'Repräsentanten' angeben, um Python-Objekte in Text zu konvertieren, und 'Konstruktoren', um den Prozess umzukehren.
quelle
from six import iteritems
und ändern Sie es danniteritems(data)
so, dass es in Python 2 & 3 gleich gut funktioniert.represent_dict
undDEFAULT_MAPPING_TAG
) zu verwenden. Liegt dies daran, dass die Dokumentation unvollständig ist, oder werden diese Funktionen nicht unterstützt und können ohne vorherige Ankündigung geändert werden?dict_constructor
Sie anrufen müssenloader.flatten_mapping(node)
oder nicht laden können<<: *...
(Syntax zusammenführen)Option 2018:
oyaml
ist ein Ersatz für PyYAML, der die Reihenfolge der Diktate beibehält . Sowohl Python 2 als auch Python 3 werden unterstützt. Einfachpip install oyaml
und wie unten gezeigt importieren:Sie werden sich beim Dumping / Laden nicht mehr über vermasselte Zuordnungen ärgern.
Hinweis: Ich bin der Autor von Oyaml.
quelle
Option 2015 (und später):
ruamel.yaml ist ein Ersatz für PyYAML (Haftungsausschluss: Ich bin der Autor dieses Pakets). Das Beibehalten der Reihenfolge der Zuordnungen war eines der Dinge, die in der ersten Version (0.1) im Jahr 2015 hinzugefügt wurden. Es behält nicht nur die Reihenfolge Ihrer Wörterbücher bei, sondern auch Kommentare, Ankernamen, Tags und unterstützt YAML 1.2 Spezifikation (veröffentlicht 2009)
Die Spezifikation besagt, dass die Reihenfolge nicht garantiert ist, aber natürlich gibt es eine Reihenfolge in der YAML-Datei, und der entsprechende Parser kann dies einfach beibehalten und transparent ein Objekt generieren, das die Reihenfolge beibehält. Sie müssen nur den richtigen Parser, Lader und Dumper auswählen¹:
werde dir geben:
data
ist vom Typ,CommentedMap
der wie ein Diktat funktioniert, aber zusätzliche Informationen enthält, die bis zum Ablegen aufbewahrt werden (einschließlich des erhaltenen Kommentars!)quelle
CommentedMap
direkt zu verwenden, aber es funktioniert nicht undOrderedDict
setzt!!omap
überall, was nicht sehr benutzerfreundlich ist.CommentedMap
withsafe=True
in zu speichernYAML
, was nicht funktioniert hat (mithilfe vonsafe=False
works). Ich hatte auch ein Problem damit,CommentedMap
nicht modifizierbar zu sein, aber ich kann es jetzt nicht reproduzieren ... Ich werde eine neue Frage öffnen, wenn ich erneut auf dieses Problem stoße.yaml = YAML()
, Sie erhalten den Round-Trip-Parser / Dumper und das ist eine Ableitung des sicheren Parsers / Dumper, der über CommentedMap / Seq usw. Bescheid weißHinweis : Es gibt eine Bibliothek, die auf der folgenden Antwort basiert und auch CLoader und CDumpers implementiert: Phynix / yamlloader
Ich bezweifle sehr, dass dies der beste Weg ist, aber das ist der Weg, den ich mir ausgedacht habe, und es funktioniert. Auch als Kernstück erhältlich .
quelle
key_node.start_mark
Attribut in Ihre Fehlermeldung aufnehmen möchten , sehe ich keinen offensichtlichen Weg, um Ihre zentrale Konstruktionsschleife zu vereinfachen. Wenn Sie versuchen, die Tatsache zu nutzen, dass derOrderedDict
Konstruktor eine Iteration von Schlüssel-Wert-Paaren akzeptiert, verlieren Sie beim Generieren der Fehlermeldung den Zugriff auf dieses Detail.add_constructor
in Ihrer__init__
Methode entfernen .Update : Die Bibliothek wurde zugunsten des yamlloader (der auf dem yamlordereddictloader basiert) veraltet.
Ich habe gerade eine Python-Bibliothek gefunden ( https://pypi.python.org/pypi/yamlordereddictloader/0.1.1 ), die basierend auf Antworten auf diese Frage erstellt wurde und recht einfach zu verwenden ist:
quelle
yodl
schauen Sie sich Github an.Bei meiner For PyYaml-Installation für Python 2.7 habe ich __init__.py, constructor.py und loader.py aktualisiert. Unterstützt jetzt die Option object_pairs_hook für Ladebefehle. Die verschiedenen Änderungen, die ich vorgenommen habe, sind unten aufgeführt.
quelle
Hier ist eine einfache Lösung, die auch nach doppelten Schlüsseln der obersten Ebene in Ihrer Karte sucht.
quelle