PyYAML ведет себя по-разному в разных ОС - PullRequest
0 голосов
/ 29 мая 2018

Я сейчас немного запутался в PyYAML.Я установил версию 3.12 на мою Windows и мою систему Linux и увидел, что при сортировке значений она ведет себя по-разному.

Давайте посмотрим на этот пример 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

Загрузка файла YAML выполняется, как обычно, через conf = yaml.load(fp).

Теперь, что действительно странно между этими двумя системами, так это то, что когда я пытаюсь выполнить все функции, я получаю различный порядок в обеих системах ОС.

В 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 голосов
/ 29 мая 2018

Прежде всего, спецификация YAML (как старая версия 1.1, на которой основан PyYAML, так и более новая спецификация 1.2 (2009)) указывают на то, что ключи отображений неупорядочены.Таким образом, вы не должны полагаться на порядок, который будет там после загрузки.

Тогда под капотом, конечно, есть разница, что Диконы Python 3.6 упорядочены (в реализации 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) и сделайте.Например:

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 с 2.7 по 3.7, как в Python 3.6.5.(в ruamel.yaml выполнение yaml.load() по умолчанию безопасно).

...