在 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。
如您所见,您松开了 OK 和 mainPC 周围的引号,而您
在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),并正确转储这些值
返回为标记的、未引用的、标量。