为什么我的循环会在我的 YAML 文件末尾添加一个额外的键值对?

Why is my loop adding an additional key value pair at the end of my YAML file?

我有两个单独的 YAML 文件,我正在使用 ruamel.yaml.

进行解析

File_one:

---
value: 600
another_value: 330
main_config::config::config:
  username:
    password: 'ENCRYPTED_PASSWORD'
    name: 'John Doe'
    role: 'admin'
    expiration: '2055-01-01'
    email: 'username@email.com'

和File_two:

---
main_config::config::config:
  username:
    password: 'ENCRYPTED_PASSWORD'
    name: 'John Doe'
    role: 'admin'
    expiration: '2055-01-01'
    email: 'username@email.com'
another_config::config:
  setting1:
    setting2:
      setting3:
        setting4: false

我正在使用 raumel 解析文件并更新到期日期,同时保留整个文件。然而,它似乎在 File_one 中有效,但在 file_two 中无效。

File_two 不仅会更新到期日期,还会在文件末尾添加一个额外的到期日期,如下所示:

---
main_config::config::config:
  username:
    password: 'ENCRYPTED_PASSWORD'
    name: 'John Doe'
    role: 'admin'
    expiration: '2055-01-01'
    email: 'username@email.com'
another_config::config:
  setting1:
    setting2:
      setting3:
        setting4: false
    expiration: '2055-01-01'

我使用的代码片段是:

with open(f"./path/to/file.yaml", 'r') as f:
    file = yaml.load(f)

    for k, v in file.items():
        if isinstance(v, dict):
            for x, y in v.items():
                if isinstance(y, dict):
                    y['expiration'] = DATE
    # Write new expiration date to file in CM:
    with open(f"./path/to/file.yaml", "w") as edit_file:
        yaml.dump(file, edit_file)

为什么使用相同代码的两个文件的输出不同?

你也许可以试试这个,

if isinstance(y, dict) and 'expiration' in y:
    y['expiration'] = DATE

所以,你的代码看起来像

with open(f"./path/to/file.yaml", 'r') as f:
    file = yaml.load(f)

    for k, v in file.items():
        if isinstance(v, dict):
            for x, y in v.items():
                if isinstance(y, dict) and 'expiration' in y:
                    y['expiration'] = DATE
    # Write new expiration date to file in CM:
    with open(f"./path/to/file.yaml", "w") as edit_file:
        yaml.dump(file, edit_file)

您的 File_one 在根级别只有一个键,该键的值是字典,并且到期日期会在其中更新。您的 File_two 在根级别有两个键,它们有一个 dict 作为值,并且它们都得到更新。因为在第二个 YAML 示例中输入不同并触发了两次“更新过期”代码,所以输出不同。这通常是正确的:如果代码的行为取决于所处理的数据,那么尽管代码相同,但不同输入的输出可能不同。

您可以添加一个额外的测试来查看 expiration 是否是字典中的键,然后再更新它(即,如果它不存在,您将永远不会添加它:

            if isinstance(y, dict) and 'expiration' in y:

,或者如果你总是想在找到的第一个dict中添加过期键,你可以退出:

            if isinstance(y, dict):
                y['expiration'] = DATE
                break

有问题的是您的代码写入一个打开的文件,同时它仍在被读取。您可以将最后两行移到初始 with 语句之外,但我建议使用 pathlib.Path 将文件正确打开为二进制文件(需要转储为 UTF-8):

from pathlib import Path
yaml_file = Path('./path/to.file.yaml')
data = yaml.load(yaml_file)

for k, v in file.items():
    if isinstance(v, dict):
        for x, y in v.items():
            if isinstance(y, dict):
                y['expiration'] = DATE
                break

# Write new expiration date to file in CM:
yaml.dump(file, yaml_file)