Wie kann ich eine YAML-Datei in Python analysieren?

611

Wie kann ich eine YAML-Datei in Python analysieren?

Szymon Lipiński
quelle

Antworten:

806

Die einfachste und reinste Methode ohne C-Header ist PyYaml ( Dokumentation ), die installiert werden kann über pip install pyyaml:

#!/usr/bin/env python

import yaml

with open("example.yaml", 'r') as stream:
    try:
        print(yaml.safe_load(stream))
    except yaml.YAMLError as exc:
        print(exc)

Und das ist es. Es gibt yaml.load()auch eine einfache Funktion, die jedoch yaml.safe_load()immer bevorzugt werden sollte, es sei denn, Sie benötigen ausdrücklich die bereitgestellte Serialisierung / Deserialisierung beliebiger Objekte, um die Möglichkeit der Ausführung von willkürlichem Code zu vermeiden.

Beachten Sie, dass das PyYaml-Projekt Versionen bis zur YAML 1.1-Spezifikation unterstützt . Wenn Unterstützung für die YAML 1.2-Spezifikation benötigt wird, lesen Sie ruamel.yaml, wie in dieser Antwort angegeben .

Jon
quelle
96
Ich würde hinzufügen, dass es besser yaml.safe_loadist, einen beliebigen Code aus der YAML-Datei auszuführen , es sei denn, Sie möchten beliebige Objekte serialisieren / deserialisieren .
ternaryOperator
4
Yaml yaml = neues Yaml (); Objekt obj = yaml.load ("a: 1 \ nb: 2 \ nc: \ n - aaa \ n - bbb");
MayTheSchwartzBeWithYou
2
Ich mag den Artikel von Elch: martin-thoma.com/configuration-files-in-python
SaurabhM
4
Möglicherweise müssen Sie zuerst das PyYAML-Paket installieren. pip install pyyamlWeitere Optionen finden Sie in
Romain
7
Was bringt es, die Ausnahme in diesem Beispiel zu erfassen? Es wird sowieso gedruckt, und es macht das Beispiel nur
komplizierter
116

Lesen und Schreiben von YAML-Dateien mit Python 2 + 3 (und Unicode)

# -*- coding: utf-8 -*-
import yaml
import io

# Define data
data = {
    'a list': [
        1, 
        42, 
        3.141, 
        1337, 
        'help', 
        u'€'
    ],
    'a string': 'bla',
    'another dict': {
        'foo': 'bar',
        'key': 'value',
        'the answer': 42
    }
}

# Write YAML file
with io.open('data.yaml', 'w', encoding='utf8') as outfile:
    yaml.dump(data, outfile, default_flow_style=False, allow_unicode=True)

# Read YAML file
with open("data.yaml", 'r') as stream:
    data_loaded = yaml.safe_load(stream)

print(data == data_loaded)

Erstellte YAML-Datei

a list:
- 1
- 42
- 3.141
- 1337
- help
- 
a string: bla
another dict:
  foo: bar
  key: value
  the answer: 42

Allgemeine Dateienden

.yml und .yaml

Alternativen

Für Ihre Anwendung kann Folgendes wichtig sein:

  • Unterstützung durch andere Programmiersprachen
  • Lese- / Schreibleistung
  • Kompaktheit (Dateigröße)

Siehe auch: Vergleich der Datenserialisierungsformate

Wenn Sie eher nach einer Möglichkeit suchen, Konfigurationsdateien zu erstellen, sollten Sie meinen kurzen Artikel Konfigurationsdateien in Python lesen

Martin Thoma
quelle
Meine Ausgabe von unter Windows ist €. Kennt jemand den Grund?
Cloud Cho
Welche Kodierung hat die Datei? Bist du sicher, dass es utf-8-codiert ist?
Martin Thoma
1
Danke für den Vorschlag. Meine Datei hat eine utf-8-Codierung. Ich musste Ihre Codezeile ändern io.open(doc_name, 'r', encoding='utf8'), um das Sonderzeichen zu lesen. YAML Version 0.1.7
Cloud Cho
Huh, interessant. Ich werde versuchen, das morgen zu reproduzieren und die Frage anpassen, wenn ich kann. Vielen Dank!
Martin Thoma
1
Sie können das integrierte Gerät open(doc_name, ..., encodung='utf8')zum Lesen und Schreiben verwenden, ohne es zu importieren io.
dexteritas
61

Wenn Sie YAML haben, das der YAML 1.2-Spezifikation (veröffentlicht 2009) entspricht, sollten Sie ruamel.yaml verwenden (Haftungsausschluss: Ich bin der Autor dieses Pakets). Es handelt sich im Wesentlichen um eine Obermenge von PyYAML, die den größten Teil von YAML 1.1 (ab 2005) unterstützt.

Wenn Sie in der Lage sein möchten, Ihre Kommentare beim Roundtripping beizubehalten, sollten Sie auf jeden Fall ruamel.yaml verwenden.

Das Upgrade von @ Jons Beispiel ist einfach:

import ruamel.yaml as yaml

with open("example.yaml") as stream:
    try:
        print(yaml.safe_load(stream))
    except yaml.YAMLError as exc:
        print(exc)

Verwenden safe_load()Sie diese Option, es sei denn, Sie haben wirklich die volle Kontrolle über die Eingabe, benötigen sie (selten) und wissen, was Sie tun.

Wenn Sie pathlib Pathzum Bearbeiten von Dateien verwenden, sollten Sie die neue API verwenden, die ruamel.yaml bietet:

from ruamel.yaml import YAML
from pathlib import Path

path = Path('example.yaml')
yaml = YAML(typ='safe')
data = yaml.load(path)
Anthon
quelle
Hallo @Anthon. Ich habe Ruamels verwendet, habe aber ein Problem mit Dokumenten erhalten, die nicht ASCII-konform sind ( UnicodeDecodeError: 'ascii' codec can't decode byte 0xe7 in position 926: ordinal not in range(128)). Ich habe versucht, yaml.encoding auf utf-8 zu setzen, aber es hat nicht funktioniert, da die Lademethode in YAML immer noch den ascii_decode verwendet. Ist das ein Fehler?
SnwBr
27

Installieren Sie Pyyaml ​​zuerst mit pip3.

Importieren Sie dann das yaml-Modul und laden Sie die Datei in ein Wörterbuch namens 'my_dict':

import yaml
with open('filename.yaml') as f:
    my_dict = yaml.safe_load(f)

Das ist alles was du brauchst. Jetzt befindet sich die gesamte yaml-Datei im Wörterbuch 'my_dict'.

Kumpel
quelle
6
Schließt dies das Dateihandle?
Yangmillstheory
2
Wenn Ihre Datei die Zeile "- Hallo Welt" enthält, ist es unangemessen, die Variable my_dict aufzurufen, da sie eine Liste enthalten wird. Wenn diese Datei bestimmte Tags enthält (beginnend mit !!python), kann die Verwendung auch unsicher sein (wie bei einer vollständig gelöschten Festplatte) yaml.load(). Da dies klar dokumentiert ist, sollten Sie diese Warnung hier wiederholt haben (in fast allen Fällen yaml.safe_load()kann verwendet werden).
Anthon
4
Sie verwenden import yaml, aber das ist kein integriertes Modul, und Sie geben nicht an, um welches Paket es sich handelt. Das Ausführen import yamlauf einer neuen Python3-Installation führt zuModuleNotFoundError: No module named 'yaml'
Cowlinator
11

Beispiel:


defaults.yaml

url: https://www.google.com

Umwelt.py

from ruamel import yaml

data = yaml.safe_load(open('defaults.yaml'))
data['url']
Prashanth Sams
quelle
Ist es sicher, den Stream nicht zu schließen?
qrtLs
3

Ich benutze ruamel.yaml . Details & Debatte hier .

from ruamel import yaml

with open(filename, 'r') as fp:
    read_data = yaml.load(fp)

Die Verwendung von ruamel.yaml ist (mit einigen einfachen lösbaren Problemen) mit alten Verwendungen von PyYAML kompatibel und wird, wie in dem von mir angegebenen Link angegeben, verwendet

from ruamel import yaml

anstatt

import yaml

und es wird die meisten Ihrer Probleme beheben.

EDIT : PyYAML ist nicht tot, wie sich herausstellt, es wird nur an einem anderen Ort gepflegt.

Oleksandr Zelentsov
quelle
@Oleksander: PyYaml hat in den letzten 7 Monaten Commits durchgeführt, und die letzte geschlossene Ausgabe war vor 12 Tagen. Können Sie bitte "lange tot" definieren?
Abalter
@abalter Ich entschuldige mich, scheint, dass ich die Informationen von ihrer offiziellen Website oder dem Beitrag hier bekommen habe stackoverflow.com/a/36760452/5510526
Oleksandr Zelentsov
@OleksandrZelentsov Ich kann die Verwirrung sehen. Es gab eine lange Zeit, als es tot war. github.com/yaml/pyyaml/graphs/contributors . Ihre Website ist jedoch aktiv und zeigt Veröffentlichungen, die NACH dem SO-Beitrag veröffentlicht wurden und sich auf PyYamls Tod beziehen. Man kann also mit Recht sagen, dass es zu diesem Zeitpunkt noch am Leben ist, obwohl seine Richtung in Bezug auf Ruamel eindeutig ungewiss ist. AUCH hier gab es eine lange Diskussion mit aktuellen Beiträgen. Ich habe einen Kommentar hinzugefügt, und jetzt ist meiner der einzige. Ich glaube, ich verstehe nicht, wie geschlossene Themen funktionieren. github.com/yaml/pyyaml/issues/145
abalter
@abalter FWIW, als diese Antwort veröffentlicht wurde, gab es in der Vergangenheit insgesamt 9 Commits ... knapp 7 Jahre. Eine davon war eine automatisierte "Korrektur" der schlechten Grammatik. Zwei davon betrafen die Veröffentlichung einer kaum veränderten neuen Version. Der Rest waren relativ kleine Änderungen, die meistens fünf Jahre vor der Antwort vorgenommen wurden. Alle außer dem automatisierten Fix wurden von einer Person durchgeführt. Ich würde diese Antwort nicht hart beurteilen, wenn ich PyYAML "lange tot" nenne.
Fund Monica Klage
-1
#!/usr/bin/env python

import sys
import yaml

def main(argv):

    with open(argv[0]) as stream:
        try:
            #print(yaml.load(stream))
            return 0
        except yaml.YAMLError as exc:
            print(exc)
            return 1

if __name__ == "__main__":
    sys.exit(main(sys.argv[1:]))
Wojciech Sciesinski
quelle
1
Dieser Code macht eigentlich nichts. Wollten Sie Code auskommentieren?
Cowlinator