使用 Python 更改 yaml 文件中的值

Posted

技术标签:

【中文标题】使用 Python 更改 yaml 文件中的值【英文标题】:Changing a value in a yaml file using Python 【发布时间】:2017-04-07 08:09:16 【问题描述】:

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

  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 技能:您的行 yaml.dump(f)with .. as f: 范围之外访问 f 不是问题吗? 您的评论很有道理,所以我试了一下,但这看起来还是不行。文件仍未写入 【参考方案1】:

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

试试这个:

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

【讨论】:

【参考方案2】:

问题是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)

【讨论】:

什么叫 YAML 结构? dump() 返回一个字符串(包含 YAML 文档),除非您指定 stream 参数(您应该这样做)。将返回的字符串写入文件是使用yaml.dump() 和糟糕建议的低效(时间和内存使用)方式。 我们不能只替换文件中对应的key,而不是自己读写完整的文件吗?【参考方案3】:

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

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)

【讨论】:

【参考方案4】:

在其他任何事情之前:不要使用yaml.load(),如果你不需要,因为原则上这样做是不安全的。对于这种简单的结构(不带标签),您应该使用yaml.safe_load()(以及相应的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),并在写入后将值作为字符串返回。

所以虽然你可以这样做:

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) 并且还在您的文件中保留 cmets。

【讨论】:

谢谢。但是 _safe_dump 函数不支持保存十进制 是什么阻碍了您将 Decimal 的代表添加到转储程序?

以上是关于使用 Python 更改 yaml 文件中的值的主要内容,如果未能解决你的问题,请参考以下文章

如何从 python 中的嵌套 YAML 文件中读取数据?

如何将 yaml 字符串插入到 yaml 值中,就好像它是 yaml

使用 ConfigParser Python 更改 ini 文件中的值

python Python - 在YAML列表中搜索要更改或插入的值

尝试从数组中的值中删除基于 MKMap 的引脚

如何为 ASP.net/C# 应用程序配置文件值中的值添加与号