【问题标题】:Reading and changing objects in .yaml file (Using PyYAML)读取和更改 .yaml 文件中的对象(使用 PyYAML)
【发布时间】:2018-12-21 18:55:21
【问题描述】:

我环顾了几个小时,除了广泛的介绍外,什么也没有。这意味着我知道的比我知道的要多。

main:
    user-settings:
        accountID: 666
        timestamp: 00:00
    client settings:
        nickname: "mainPC"
        region: "OK"

例如,如何打印“accountID”和“region”?

如果我想将 accountID 从 666 更改为 102,我该怎么做?

【问题讨论】:

  • 有一个问题here 带有如何处理此问题的示例代码。
  • 您认为调用accountID 会产生什么结果?加载后 accountId 是 Python dict 中的关键,而不是可调用的东西。更改accountId 是什么意思。您想更改键并保持相同的值,还是想更改与该映射中的键关联的值(如果是这样,您应该以明确的方式说明)。
  • @Anthon 说得更清楚了。很抱歉造成混乱。

标签: python yaml pyyaml


【解决方案1】:

在 PyYAML 中你不能真正做到你所要求的,即使是小的 你有的例子。打印请求的值有效,但是当您更新时 你的 YAML 你会看到它改变了几个输出行 除了accountID 的值。假设您的 YAML 文件是 test.yaml:

from pathlib import Path
import yaml

yaml_file = Path('test.yaml')

with yaml_file.open() as fp:
    data = yaml.safe_load(fp)
user_settings = data['main']['user-settings']
print('acount id:', user_settings['accountID'])
user_settings['accountID'] = 102
print('region:   ', data['main']['client settings']['region'])

with yaml_file.open('w') as fp:
    yaml.safe_dump(data, fp, indent=4, default_flow_style=False)

这个输出:

acount id: 666
region:    OK

test.yaml 的内容将是:

main:
    client settings:
        nickname: mainPC
        region: OK
    user-settings:
        accountID: 102
        timestamp: 00:00

你会得到一个 Python dict 用于 YAML 文件中的任何映射,以及一个 Python list 如果你的 YAML 中有一个序列。打印一个 你想要的值,你只需遍历嵌套的dicts。

如您所见,您松开了 OKmainPC 周围的引号,而您 在00:00 附近获得他们。后者是因为 PyYAML 还没有 更新以处理重新发布的当前 YAML 1.2 标准 2009. 在 YAML 1.1 中,XX:YY 形式的标量假定为 sexagesimals 和 转换(并转储)为整数(或浮点数,如果有 小数点)。您的 00:00 被加载为字符串是因为 前导零。如果它是12:00,那么您的输出文件将 是timestamp: 720

映射中键的顺序也不是 保存。语义上这没有区别,但如果这个文件是 在修订控制下,此类更改很快就会变得混乱。

您应该使用safe_load(),因为“标准”load() 可能不安全 在不受控制的 YAML 输入上,虽然有记录,但大多数人没有 意识到这一点,也不是本质上没有必要。 (不安全的 在“硬盘擦除”中,或更糟。)


如果你想更新 YAML 文件,我建议使用 ruamel.yaml(免责声明:我 我是那个包的作者)。

from pathlib import Path
import ruamel.yaml

yaml_file = Path('test.yaml')

yaml = ruamel.yaml.YAML()
yaml.indent(mapping=4)
yaml.preserve_quotes = True
data = yaml.load(yaml_file)

user_settings = data['main']['user-settings']
print('acount id:', user_settings['accountID'])
user_settings['accountID'] = 102
print('region:   ', data['main']['client settings']['region'])

yaml.dump(data, yaml_file)

也输出:

acount id: 666
region:    OK

test.yaml 的内容将是:

main:
    user-settings:
        accountID: 102
        timestamp: 00:00
    client settings:
        nickname: "mainPC"
        region: "OK"

不仅可以正确保留引号,而且不必 引用 00:00,因为 ruamel.yaml 处理 YAML 1.2,其中 六十进制完全删除¹。映射中键的顺序 被保留。

如果test.yaml 中有 cmets,那么PyYAML 会丢弃这些, 而ruamel.yaml 也保留这些。

ruamel.yaml 中,默认YAML() 使用安全加载程序。


¹如果您创建 Sexagesimal,您仍然可以使用六十进制数 分类并适当地标记它们。在这种情况下,您也可以决定 有前导零(!sexagesimal 00:00),并正确转储这些值 返回为标记的、未引用的、标量。

【讨论】:

    猜你喜欢
    • 2021-05-17
    • 2015-10-23
    • 2023-03-26
    • 2016-09-12
    • 2023-04-01
    • 2023-03-03
    • 1970-01-01
    • 1970-01-01
    • 2011-03-15
    相关资源
    最近更新 更多