我们先来写一个测试用的yaml
文件
name: test yaml data
no: 1
file_path: /dir/test.yaml
data:
on: PC
is_long: yes
然后再来写一段python
来读取这个yaml
文件的内容
import yaml
def read_yaml():
with open('./test.yaml', 'r', encoding='utf-8') as f:
data = yaml.load(f, Loader=yaml.Loader)
return data
调用read_yaml()
方法,读取内容,打印出来,如下:
{
"name":"test yaml data",
False:1,
"file_path":"/dir/test.yaml",
"data":{
True:"PC",
"is_long":True
}
}
对比原始的yaml
文件可以看到
- 值为
1
的字段名在原始文件是no
,但是读取出来后是False
- 值为
PC
的字段名在原始文件是on
,但是读取出来后是True
- 字段
is_long
的原始值为yes
,但是读取出来后是True
可以发现,no
变成了False
,on
和yes
变成了True
,好像触发了什么神秘代码,隐隐约约又像有点规律,这是为什么呢?
经过一番打断点的调试折腾,发现在yaml
源码/site-packages/yaml/resolver.py
里第170
行有这么一段代码:
Resolver.add_implicit_resolver(
'tag:yaml.org,2002:bool',
re.compile(r'''^(?:yes|Yes|YES|no|No|NO
|true|True|TRUE|false|False|FALSE
|on|On|ON|off|Off|OFF)$''', re.X),
list('yYnNtTfFoO'))
解析下就是,当正则匹配到yes|Yes|YES|no|No|NO|true|True|TRUE|false|False|FALSE|on|On|ON|off|Off|OFF
等内容时,一律把这个内容当成一个bool
类型的值,bool
类型的值那就是True
或者False
继续寻找,在/site-packages/yaml/constructor.py
里第216
行有这么一段代码:
bool_values = {
'yes': True,
'no': False,
'true': True,
'false': False,
'on': True,
'off': False,
}
这里定义了一个字典,字典里面的key
分别对应了不同的bool
值
再观察下,发现这些key
正是上面正则表达式里的内容,所以,这里的逻辑就是读取yaml
文件时,会根据不同的内容给该内容一个标签,是列表或者字典或者字符串或者bool
类型或者float
型,判断属于哪种类型都是根据正则表达式来匹配的,而当匹配到
yes|Yes|YES|no|No|NO|true|True|TRUE|false|False|FALSE|on|On|ON|off|Off|OFF
时,把他当做bool
类型,又根据bool_values
里面的定义,no
就是False
,on
就是True
,yes
就是True
,所以我们上面的yaml
读取出来后,内容与原始文件不一样,原因就是如此。
再查阅一番,找到YAML
官网关于bool的介绍,确实是这样,这些也正是yaml
语言所规定的格式,可以理解为这些是yaml
语言的内置关键字,类似于python
里面的内置关键字,尽量的避免使用他们来作为内容。
如果确实需要用到这些特殊的名称,又不想让他变成bool
类型,可以使用引号将其变为字符串,例如:
name: test yaml data
'no': 1
file_path: /dir/test.yaml
data:
'on': PC
is_long: 'yes'
这样再读取出来就没有问题了。