yaml.load, принудительно вводить ключи в строки - PullRequest
0 голосов
/ 26 апреля 2018

В Python3 я загружаю кусок YAML. Загрузчик пытается угадать правильные типы, но я не совсем доволен. Я хочу, чтобы ключи dict всегда были строками.

Сначала продемонстрируйте минималистичный фрагмент YAML, который легко вставить прямо в ваш интерпретатор Python. Излишне говорить, что мои данные в реальном мире намного сложнее.

txt = """
---
one: 1
2: two
"""

Сначала «обычная» нагрузка:

yaml.load(txt)
{2: 'two', 'one': 1}

Обратите внимание, как ключ 2 был загружен как число, а не как строка. Тогда давайте попробуем что-то другое:

yaml.load(txt, Loader=yaml.BaseLoader)
{'2': 'two', 'one': '1'}

Теперь все сделано в виде строк. К сожалению также 1 , который, как значение, мне нужен как число.

Таким образом, у меня могут быть как ключи, так и значения, принудительно заданные для строк, или ни одного.

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

Предложения

Ответы [ 2 ]

0 голосов
/ 26 апреля 2018

Вы можете сделать это с помощью нескольких строк кода, меняя каждое построенное отображение так, чтобы ключи целочисленного типа преобразовывались в строки на лету. Вы можете создать подкласс SafeLoader, но тогда вам нужно зарегистрировать конструкторы. Проще всего исправить конструктор сопоставления:

import yaml

def my_construct_mapping(self, node, deep=False):
    data = self.construct_mapping_org(node, deep)
    return {(str(key) if isinstance(key, int) else key): data[key] for key in data}

yaml.SafeLoader.construct_mapping_org = yaml.SafeLoader.construct_mapping
yaml.SafeLoader.construct_mapping = my_construct_mapping


yaml_str = """\
---
one: 1
2: two
"""

data = yaml.safe_load(yaml_str)
print(data)

, что дает:

{'one': 1, '2': 'two'}

Нет причины использовать значение по умолчанию, unsafe , yaml.load() (т.е. без параметра Loader=).

0 голосов
/ 26 апреля 2018

Поискивая код в библиотеке yaml, похоже, что создание собственного загрузчика для выполнения всего этого за один проход было бы довольно большой задачей. Если у вас нет особенно большого файла yaml, который вы пытаетесь обработать, и вам действительно нужно избегать второго прохода, просто пост-обработка с пониманием словаря, вероятно, будет проще всего:

In [15]: {str(k): v for k, v in yaml.load(txt).items()}
Out[15]: {'2': 'two', 'one': 1}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...