我尝试使用python在YAML文件中进行一些更改。 我有一个结构文件:
name:
mode: value
该值是十六进制数字的数字。 我这样做:
import ruamel.yaml as yaml
f = open('C:\\file.yaml', 'r')
data = yaml.load(f, Loader=yaml.RoundTripLoader)
然后更改几个值并将其转储回来:
with open('C:\\file.yaml', 'w') as out_yaml:
yaml.dump(in_data, out_yaml, Dumper=yaml.RoundTripDumper, explicit_start=True)
这里我有一个问题 - 一些值被加载为int或float,并且在转储之后我得到诸如.inf
或9.4014e+40
之类的值,例如来自YAML:
name:
mode1: 8578E877
mode2: 94014E36
如何保留此类转换的结果值?
答案 0 :(得分:2)
你声明"该值是一些十六进制数"和"一些值被加载为int或float"。根据用于往返加载的YAML 1.2. Core Schema(以及更简单的JSON模式):这些标量 int
。 float
而非字符串。
如果您尝试将具有各种字符组合的结构转储为字符串:
import sys
from ruamel import yaml
data = dict(
name=dict(
teny='decade',
tbig='8578E877',
mode='94014E36',
ints='12345',
Bool='True',
)
)
yaml.round_trip_dump(data, sys.stdout)
你会得到:
name:
teny: decade
tbig: '8578E877'
mode: '94014E36'
ints: '12345'
Bool: 'True'
正如您所看到的,只有decade
将其标记为不带引号的标量,其原因在于,如果没有引用其他标题,则可能会误解其他标记。
这就是为什么,如果你看看如何构建RoundTripLoader
和RoundTripDumper
(及其安全和不安全的对应物),你可以看到两者来自Resolver
。即使在转储值时,模式中的模式也会与附加到Resolver
的正则表达式进行匹配,以确保它不会作为特殊类型加载回来。由于YAML输出中引用的True
表示这也适用于int
和float
以外的其他类型。
简单的解决方案是在YAML输入中引用十六进制数字的组合:
import sys
from ruamel import yaml
yaml_str = """\
name:
tbig: '8578E877'
mode: '94014E36'
"""
data = yaml.round_trip_load(yaml_str)
print(data['name']['tbig'], data['name']['mode'], end='\n----\n')
yaml.round_trip_dump(data, sys.stdout)
将打印:
8578E877 94014E36
----
name:
tbig: '8578E877'
mode: '94014E36'
可以防止这些标量字符串作为int
加载。 float
。如果您通过更改附加到Resolver
的正则表达式来执行此操作,您的程序将以不再遵循核心架构的方式加载并转储,因此引号不会附加在必要时自动转储。
如果现有YAML文件中的值太多而无法手动更改,并希望进行一次性转换,则您需要使用具有解析程序的Loader
。使用这些模式。幸运的是BaseLoader
这样做了:
import sys
from ruamel import yaml
yaml_str = """\
name:
tbig: 8578E877
mode: 94014E36
teny: DECADE
"""
data = yaml.load(yaml_str, yaml.loader.BaseLoader)
yaml.round_trip_dump(data, sys.stdout)
给出:
name:
tbig: '8578E877'
mode: '94014E36'
teny: DECADE
仅在必要时添加引号。在那次一次性抛负载之后,您可以在该文件上使用正常的往返或安全加载器。
我给出的第一个例子的YAML输出中的键与dict中给出的顺序相同。对于Python 3.6来说就是这样,但是在运行2.7时却没有。如果从Python数据结构开始并希望控制该输出顺序,请使用ruamel.yaml.comments.CommentedMap
而不是dict。