使用 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 文件中的值的主要内容,如果未能解决你的问题,请参考以下文章
如何将 yaml 字符串插入到 yaml 值中,就好像它是 yaml
使用 ConfigParser Python 更改 ini 文件中的值