【问题标题】:How to access & modify the content of yaml file from python?如何从python访问和修改yaml文件的内容?
【发布时间】:2017-11-09 03:02:24
【问题描述】:

我想访问和修改如下所示的 YAML 文件的内容:

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

我知道为了访问和修改上述 YAML 文件中 A 的值,我会使用如下代码:

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)

但是如果我想修改上述 YAML 文件中E 的值怎么办?如何访问E 的值并修改其值并将其转储到 YAML 文件中,类似于上面的代码。我查看了参考文档,但无法找到答案。

【问题讨论】:

  • 嵌套字典用法? doc['B']['C']?不确定 pyyaml 是如何工作的,但只要打印出 doc['B'] 给你的东西,如果它是一个 dict,那么,很简单。
  • doc['B']['C'] .. 它有效!.. 它有效.. 非常感谢.. 想知道我怎么错过了这个!
  • 永远不要使用 PyYAML yaml.load(),没有必要也不安全。
  • @Anthon 请问您推荐的备用保险箱是什么?
  • 它被称为:safe_load 所以改为yaml.safe_load()。还有一个 safe_dump() 不会尝试转储任何和所有 Python 对象而不会抱怨,但这已经足够了,您只需使用 dict/list 和原语(bool、string、int、float、datetime)跨度>

标签: python yaml pyyaml


【解决方案1】:

如果您想更改 E 的值,例如到2 您可以执行以下操作:

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)

获取E 的值B 上的第一个索引。

根据我的经验,这有很多问题:

  1. 您正在使用 load() 在 PyYAML 中是不安全的操作,没有警告。您的数据可以使用safe_load() 加载,即使不能,扩展safe_load() 以处理标签(并且仅处理这些标签)比扩展load() 要好得多。

  2. 你的输出看起来像:

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

    一点也不喜欢你的输入,所以使用选项default_flow_style=False 用你原来的块式布局获得一些东西。

  3. 您不需要dump(),因为由dicts 和原语(和列表)组成的数据可以用safe_dump() 转储。那里没有安全问题,但如果你不小心用非原始类型调用set_state()

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

    然后dump() 将静默生成不可移植:

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

    而不是引发Representer 错误。

  4. 原始文件中的所有 cmets 都将丢失。 PyYAML 不保留这些。

使用 PyYAML 你应该这样做:

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)

如果您还想保留 cmets,或者想要保留块样式和流样式的混合,我建议您使用ruamel.yaml(免责声明:我是该包的作者):

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)

这与以前的结果相同,默认情况下load() 方法是安全的,保留您的布局(以及您可能拥有的 YAML 文件中的任何 cmets)并打开Path 实例以根据需要进行读取或写入(因此您不需要with 语句,也不需要调用dump 并将w 提供给open() 的双重操作。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-03-23
    • 1970-01-01
    • 1970-01-01
    • 2014-07-24
    • 1970-01-01
    • 2019-03-04
    • 2010-12-09
    • 1970-01-01
    相关资源
    最近更新 更多