使用 Python 更改 yaml 文件中的值

Changing a value in a yaml file using Python

我有一个 .yaml 文件,我想用 Python 代码更新。假设它看起来像这样:

  state: 'present'

我想要一个更改状态并保存文件的代码。我正在尝试这样的事情但失败了:

def set_state(state):
    with open("file_to_edit.yaml", 'rw') as f:
        doc = yaml.load(f)
    doc['state'] = state
    yaml.dump(f)

我正在为 Python 使用 'yaml' 包。

我猜你没有正确缩进,因为你的函数在其当前状态下似乎没有做任何事情。 Python 关心缩进。

试试这个:

    def set_state(state):
        with open("file_to_edit.yaml", 'rw') as f:
            doc = yaml.load(f)
        doc['state'] = state
        yaml.dump(f)

问题是 yaml.dump(doc) 实际上并没有写入文件。相反,it returns the modified YAML as a string 除非您也将文件描述符作为参数传递,这允许您直接写入文件。

以下应该有效:

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

    doc['state'] = state

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

您可以尝试以下操作(它会创建一个新文件来存储结果):

with open("output_file", 'a') as out:
    with open("input_file", 'r') as f:
        for line in f:
            line = re.sub(r"state: present", "state: installed", line)
            out.write(line)

首先:如果没有必要,请永远不要使用 yaml.load(),因为原则上这样做是不安全的。对于这种简单的结构(没有标签),你应该使用 yaml.safe_load()(如果你的数据在转储后不能 safe_loaded,相应的 safe_dump() 会抱怨)。

yaml.dump() 具有以下签名:

def dump(documents, stream=None, Dumper=Dumper,
         default_style=None, default_flow_style=None,
         canonical=None, indent=None, width=None,
         allow_unicode=None, line_break=None,
         encoding='utf-8', explicit_start=None, explicit_end=None,
         version=None, tags=None)

其中只有第一个需要给出,那应该是您的 doc 变量。如果不指定流,则 dump() 将数据结构写入内存中的文件对象(如 StringIO),并在写入 returns 后将值作为字符串。

所以尽管你可以这样做:

with open("file_to_edit.yaml", 'w') as f:
    f.write(yaml.safe_dump(doc))

这是低效的,并且对 yaml.safe_dump() 的工作原理知之甚少。

如果你想打开文件进行读写,你必须确保你都重置了文件中的索引并且截断了它的内容。这通常是不值得的,因此重新打开文件进行写入更安全:

def set_state(state):
    file_name = "file_to_edit.yaml"
    with open(file_name) as f:
        doc = yaml.safe_load(f)
    doc['state'] = state
    with open(file_name, 'w') as f:
        yaml.safe_dump(doc, f, default_flow_style=False)

(当然,当你想确保覆盖原始文件时,你将文件名设为变量,这样你就不会输错它)。

如果您不指定 default_flow_style=False,您的输出将如下所示:

{state: deleted}

输出将不包括输入中 present 周围的多余引号。您也可以指定 default_style="'",但这也会在 state.
周围加上引号 如果丢失引号是个问题并且您确实希望输出看起来像输入,则应该使用 ruamel.yaml (免责声明我是该包的作者),它可以保留单个字符串上的引号,处理 YAML 1.2(而不是 YAML 1.1)并且还在您的文件中保留注释。