如何使用来自另一个字典中匹配键的值更新 YAML 文件?

How to update YAML file with value coming from a matching key in another dictionary?

我有一个名为 input.yaml 的 YAML 文件:

---
'001':
  name: Ben
  email: ben@test.com
'002':
  name: Lisa
  email: lisa@test.com
'003':
  name: Alex
  email: alex@test.com
.
.
.

我有字典:

my_dict = {'001': '000-111-2222', '002': '000-111-2223', '003': '000-111-2224', ...}

我想要一个名为 output.yaml 的更新文件,如下所示:

---
'001':
  name: Ben
  email: ben@test.com
  phone: 000-111-2222
'002':
  name: Lisa
  email: lisa@test.com
  phone: 000-111-2223
'003':
  name: Alex
  email: alex@test.com
  phone: 000-111-2224
.
.
.

请注意输出文件如何添加 "phone" 字段以及来自匹配键的字典值的值。

如何获得这样的文件? ... 各种都试过了

除了读取和写入文件之外,也许这会为您指明正确的方向:

import yaml


document = """
---
'001':
  name: Ben
  email: ben@test.com
'002':
  name: Lisa
  email: lisa@test.com
'003':
  name: Alex
  email: alex@test.com
"""

phones = {'001': '000-111-2222', '002': '000-111-2223', '003': '000-111-2224'}

doc = yaml.safe_load(document)

for k, v in phones.items():
    # Might want to check that 'doc[k]' exists
    doc[k]['phone'] = v

print(yaml.safe_dump(doc, default_flow_style=False, explicit_start=True))

输出:

'001':
  email: ben@test.com
  name: Ben
  phone: 000-111-2222
'002':
  email: lisa@test.com
  name: Lisa
  phone: 000-111-2223
'003':
  email: alex@test.com
  name: Alex
  phone: 000-111-2224

如果您担心文件的格式保持不变(并且如果有注释应该保留),您可以这样做:

import ruamel.yaml

yaml = ruamel.yaml.YAML()
yaml.preserve_quotes = True
yaml.explicit_start = True

with open('input.yaml') as fp:
    data = yaml.load(fp)

my_dict = {
    '001': '000-111-2222',
    '002': '000-111-2223',
    '003': '000-111-2224',
}

for k in my_dict:
    data.setdefault(k, {})['phone'] = my_dict[k]

with open('output.yaml', 'w') as fp:
    yaml.dump(data, fp)

之后 output.yaml 包含:

---
'001':
  name: Ben
  email: ben@test.com
  phone: 000-111-2222
'002':
  name: Lisa
  email: lisa@test.com
  phone: 000-111-2223
'003':
  name: Alex
  email: alex@test.com
  phone: 000-111-2224

备注:

  1. yaml.preserve_quotes = True 并不是真正必要的,因为对于需要引号的标量(您的字符串以零开头)单引号是默认的,并且您的输入中也没有多余的引号.

  2. 我使用 data.setdefault(k, {})['phone'] 而不是检查 data[k] 是否存在,正如@Aaron 在他的来源中所建议的那样。如果键 k 不在 data.

  3. 中,它将创建一个(空)字典
  4. 如果您只想更新 匹配的 键,则在 for 循环中使用以下内容:

    try:
        data[k]['phone'] = my_dict[k]
    except KeyError:
        pass
    
  5. 您需要 yaml.explicit_start = True 才能在文档开头获得 ---ruamel.yaml 不会自动保留它。如果您还需要文档结束标记 (...),请使用:yaml.explicit_end = True

  6. 如果你想让phone号出现在nameemail之间,那么使用:

    data.setdefault(k, {}).insert(1, 'phone', my_dict[k])
    

    给出:

    ---
    '001':
      name: Ben
      phone: 000-111-2222
      email: ben@test.com
    '002':
      name: Lisa
      phone: 000-111-2223
      email: lisa@test.com
    '003':
      name: Alex
      phone: 000-111-2224
      email: alex@test.com
    

    (即0表示在第一个键之前插入,1在第二个键之前等)