PyYAML在不同的OS中表现不同

时间:2018-05-29 13:52:51

标签: python pyyaml

我目前对PyYAML有点困惑。我在我的Windows和Linux系统上安装了3.12版,并且看到它在排序值时表现不同。

让我们看看这个示例YAML文件:

functions:
    function_a:
        value_1: 1
        value_2: 1
        value_3: 1
    function_c:
        value_1: 1
        value_2: 1
        value_3: 1
    function_d:
        value_1: 1
        value_2: 1
        value_4: 1
    function_b:
        value_1: 1
        value_2: 1
        value_3: 1

通过conf = yaml.load(fp)照常加载YAML文件。

现在,这两个系统之间真正奇怪的是,当我尝试通过所有功能时,我在两个操作系统上都获得了不同的顺序。

在Windows上它将是:

import yaml
with open('myyamlfile.yml') as fp:
    conf = yaml.load(fp)
for function in conf['functions']:
    print(function)

function_a
function_c
function_d
function_b

在Linux上,它以有序的方式出现:

import yaml
with open('myyamlfile.yml') as fp:
    conf = yaml.load(fp)
for function in conf['functions']:
    print(function)

function_a
function_b
function_c
function_d

我真的不知道为什么。我在具有相同模块版本的两台机器上使用相同的代码。两台机器之间的唯一区别是操作系统和事实,在Windows上我使用的是3.6.5,而在Linux上我使用的是3.4.8。

有没有人暗示我为什么会这样?

1 个答案:

答案 0 :(得分:1)

首先,YAML规范(PyYAML所基于的旧1.1以及较新的1.2规范(2009))都表明映射的键是无序的。因此,您不应该在加载后依赖订单。

然后在幕后,当然存在差异Python 3.6 dicts are ordered(在CPython实现中,在其他实现中以3.7开头),而Python 3.6之前的序列不是有序的。 PyYAML创建一个dict并按照从YAML文档中读取键的顺序填充它,因此3.6.5版本获得了键插入的顺序,3.4.8没有。

如果您需要两个版本的行为相同,我建议您明确对键进行排序:

for function in sort(conf['functions']):

如果您确实需要按照YAML文档中的顺序获取密钥,我建议您查看ruamel.yaml(免责声明:我是YAML 1.2兼容软件包的作者)并且确实如此。 e.g:

import pathlib
import ruamel.yaml

yaml = ruamel.yaml.YAML()
file_name = pathlib.Path('myfile.yaml')
conf = yaml.load(file_name)
for function in conf['functions']:
    print(function)

它将在Python 3.6.5中为您提供Python 2.7到3.7中的输出。 (在ruamel.yaml中,yaml.load()默认是安全的。)