2017-06-07 2 views
0

Ich möchte den Inhalt einer YAML-Datei zugreifen und diese ändern, die das sieht wie folgt aus:Wie kann ich den Inhalt der YAML-Datei von Python aus bearbeiten?

A: Sonstige 
B: 
    C: Sonstige 
    D: null 
    E: 1 

Ich weiß, dass, um & ändern Sie den Wert von A in der oben YAML-Datei zugreifen möchte ich nutzen Code wie folgt aus:

def set_state(state): 
    with open('my_file.yaml') as f: 
     doc = yaml.load(f) 

    doc['A'] = state 

    with open('my_file.yaml', 'w') as f: 
     yaml.dump(doc, f) 

Aber was, wenn ich möchte den Wert von E in der oben YAML-Datei ändern? Wie kann ich auf den Wert E zugreifen und seinen Wert ändern und in einer YAML-Datei ausgeben, ähnlich wie im obigen Code. Ich habe die Referenzdokumente durchgegangen und konnte keine Antwort darauf finden.

+2

Verschachtelte Wörterbuch-Verwendung? '' 'doc ['B'] ['C']' ''? Nicht sicher, wie Pyyaml ​​funktioniert, aber drucken Sie einfach aus, was '' 'doc ['B']' '' Ihnen gibt, wenn es ein Diktat ist, gut, einfach. – sascha

+1

doc ['B'] ['C'] .. Es funktioniert! .. Es funktioniert .. Vielen Dank .. Frage mich, wie ich das verpasst habe! –

+0

Verwenden Sie niemals PyYAML 'yaml.load()', es ist nicht notwendig und unsicher. – Anthon

Antwort

1

Wenn Sie den Wert für E, z. zu 2 könnten Sie Folgendes tun:

import yaml 

def set_state(state): 
    with open('my_file.yaml') as f: 
     doc = yaml.load(f) 

    doc['B']['E'] = state 

    with open('my_file.yaml', 'w') as f: 
     yaml.dump(doc, f) 

set_state(2) 

auf den Wert von E ersten Index auf B zu erhalten.

Es gibt mehrere Probleme mit diesem in meiner Erfahrung:

  1. Sie verwenden load(), die in PyYAML ist ein unsicherer Betrieb ohne Vorwarnung. Ihre Daten können mit safe_load() geladen werden, und selbst wenn es nicht möglich ist, ist es viel besser, safe_load() zu erweitern, um Tags (und nur diese Tags) zu behandeln, als load() zu erweitern.

  2. Ihre Ausgabe wie folgt aussieht:

    A: Sonstige 
    B: {C: Sonstige, D: null, E: 2} 
    

    nicht wie Sie Ihre Eingabe, so verwenden Sie die Option default_flow_style=False etwas mit dem Original-Block-Layout zu erhalten.

  3. Sie benötigen nicht dump(), da Daten, die aus dict s bestehen, und Grundelemente (und Listen) können mit safe_dump() ausgegeben werden. Es gibt kein Sicherheitsproblem gibt, aber wenn Sie set_state() nennen würden aus Versehen mit einem nicht-primitiver:

    class Dice: 
        def __init__(self, sides): 
         self.sides = sides 
    
    set_state(Dice(6)) 
    

    dann dump() ohne weiteren Kommentar den nicht-portable erzeugen:

    A: Sonstige 
    B: 
        C: Sonstige 
        D: null 
        E: !!python/object:__main__.Dice {sides: 6} 
    

    statt Heben einen Representer Fehlers .

  4. Alle Kommentare in Ihrer Originaldatei gehen verloren. PyYAML bewahrt diese nicht.

Mit PyYAML sollten Sie tun:

import yaml 

def set_state(state): 
    with open('my_file.yaml') as f: 
     doc = yaml.safe_load(f) 

    doc['B']['E'] = state 

    with open('my_file.yaml', 'w') as f: 
     yaml.safe_dump(doc, f, default_flow_style=False) 

set_state(2) 

Wenn Sie auch Kommentare erhalten möchten, oder eine Mischung aus Block-Stil und Flow-Stil, den Sie beibehalten möchten haben, empfehle ich Ihnen ruamel.yaml verwenden (Disclaimer: ich bin der Autor dieses Paket):

import pathlib 
from ruamel.yaml import YAML 

def set_state(state): 
    yaml = YAML() 
    mf = pathlib.Path('my_file.yaml') 
    doc = yaml.load(mf) 

    doc['B']['E'] = state 

    yaml.dump(doc, mf) 

Dies hat das gleiche Ergebnis wie zuvor, mit der load() Methode standardmäßig sicher zu sein, die Erhaltung Ihr Layout (plus alle Kommentare in der YAML-Datei, die Sie möglicherweise haben) und öffnen Sie die Path Instanz zum Lesen oder Schreiben wie erforderlich (so dass Sie nicht die with Anweisung benötigen, noch die doppelte Aktion des Aufrufs dump und die w zu open()).

Verwandte Themen