Как я могу разобрать файл YAML в Python

Ответы:

807

Самым простым и чистым методом без использования заголовков C является PyYaml ( документация ), который можно установить с помощью pip install pyyaml:

#!/usr/bin/env python

import yaml
import json

with open("example.yaml", 'r') as stream:
    try:
        print(yaml.safe_load(stream))
    except yaml.YAMLError as exc:
        print(exc)

И это все. Простая yaml.load()функция также существует, но она yaml.safe_load()всегда должна быть предпочтительной, если вам явно не нужна произвольная сериализация / десериализация объектов, чтобы избежать возможности произвольного выполнения кода.

Обратите внимание, что проект PyYaml поддерживает версии вплоть до спецификации YAML 1.1 . Если требуется поддержка спецификации YAML 1.2 , см. Ruamel.yaml, как указано в этом ответе .

Джон
источник
96
Я хотел бы добавить, что если вы не хотите сериализовать / десериализовать произвольные объекты, лучше использовать, yaml.safe_loadпоскольку он не может выполнить произвольный код из файла YAML.
ternaryOperator
4
Yaml yaml = новый Yaml (); Object obj = yaml.load ("a: 1 \ nb: 2 \ nc: \ n - aaa \ n - bbb");
MayTheSchwartzBeWithYou
2
Мне нравится статья лося: martin-thoma.com/configuration-files-in-python
SaurabhM
4
Возможно, вам сначала потребуется установить пакет PyYAML. Дополнительные сведения pip install pyyamlсм. В этом сообщении stackoverflow.com/questions/14261614/…
Romain
7
Какой смысл захватывать исключение в этом примере? Это все равно будет печатать, и это только делает пример более запутанным ..
naught101
116

Чтение и запись файлов YAML с Python 2 + 3 (и Unicode)

# -*- coding: utf-8 -*-
import yaml
import io

# Define data
data = {
    'a list': [
        1, 
        42, 
        3.141, 
        1337, 
        'help', 
        u'€'
    ],
    'a string': 'bla',
    'another dict': {
        'foo': 'bar',
        'key': 'value',
        'the answer': 42
    }
}

# Write YAML file
with io.open('data.yaml', 'w', encoding='utf8') as outfile:
    yaml.dump(data, outfile, default_flow_style=False, allow_unicode=True)

# Read YAML file
with open("data.yaml", 'r') as stream:
    data_loaded = yaml.safe_load(stream)

print(data == data_loaded)

Создан YAML файл

a list:
- 1
- 42
- 3.141
- 1337
- help
- 
a string: bla
another dict:
  foo: bar
  key: value
  the answer: 42

Общие окончания файлов

.yml а также .yaml

альтернативы

Для вашего приложения может быть важно следующее:

  • Поддержка другими языками программирования
  • Чтение / запись производительности
  • Компактность (размер файла)

Смотрите также: Сравнение форматов сериализации данных

Если вы предпочитаете создавать файлы конфигурации, вы можете прочитать мою короткую статью Файлы конфигурации в Python

Мартин Тома
источник
Мой вывод на Windows есть €. Кто-нибудь знает причину?
Облако Чо
Какая кодировка у файла? Вы уверены, что это кодировка utf-8?
Мартин Тома
1
Спасибо за предложение. Мой файл имеет кодировку utf-8. Мне пришлось изменить строку кода, io.open(doc_name, 'r', encoding='utf8')чтобы прочитать специальный символ. YAML версия 0.1.7
Cloud Cho
Да, интересно. Я постараюсь воспроизвести это завтра и уточню вопрос, если смогу. Спасибо!
Мартин Тома
1
Вы можете использовать встроенный open(doc_name, ..., encodung='utf8')для чтения и записи, без импорта io.
dexteritas
62

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

Если вы хотите сохранить свои комментарии при циклическом переключении, вам, безусловно, следует использовать ruamel.yaml.

Обновление примера @ Jon легко:

import ruamel.yaml as yaml

with open("example.yaml") as stream:
    try:
        print(yaml.safe_load(stream))
    except yaml.YAMLError as exc:
        print(exc)

Используйте, safe_load()если у вас нет полного контроля над входом, он нужен (редко бывает) и знает, что вы делаете.

Если вы используете pathlib Pathдля манипулирования файлами, вам лучше использовать новый API ruamel.yaml:

from ruamel.yaml import YAML
from pathlib import Path

path = Path('example.yaml')
yaml = YAML(typ='safe')
data = yaml.load(path)
Энтон
источник
Привет @Антон. Я использовал руамель, но получил проблему с документами, которые не соответствуют требованиям ascii ( UnicodeDecodeError: 'ascii' codec can't decode byte 0xe7 in position 926: ordinal not in range(128)). Я попытался установить yaml.encoding в utf-8, но не работал, так как метод загрузки в YAML все еще использует код ascii_decode. Это ошибка?
SnwBr
27

Сначала установите pyyaml, используя pip3.

Затем импортируйте модуль yaml и загрузите файл в словарь под названием «my_dict»:

import yaml
with open('filename.yaml') as f:
    my_dict = yaml.safe_load(f)

Это все, что вам нужно. Теперь весь файл yaml находится в словаре my_dict.

собутыльник
источник
6
Это закрывает дескриптор файла?
yangmillstheory
2
Если ваш файл содержит строку «- hello world», то нецелесообразно вызывать переменную my_dict, поскольку она будет содержать список. Если этот файл содержит определенные теги (начиная с !!python), он также может быть небезопасным (как в случае полной очистки жесткого диска) для использования yaml.load(). Поскольку это четко задокументировано, вы должны повторить это предупреждение здесь (почти во всех случаях yaml.safe_load()можно использовать).
Энтон
4
Вы используете import yaml, но это не встроенный модуль, и вы не указываете, какой это пакет. Запуск import yamlна новой установке Python3 приводит кModuleNotFoundError: No module named 'yaml'
cowlinator
11

Пример:


defaults.yaml

url: https://www.google.com

environment.py

from ruamel import yaml

data = yaml.safe_load(open('defaults.yaml'))
data['url']
Прашант Самс
источник
это сохранить, чтобы не закрыть поток?
qrtLs
3

Я использую ruamel.yaml . Подробности и дебаты здесь .

from ruamel import yaml

with open(filename, 'r') as fp:
    read_data = yaml.load(fp)

Использование ruamel.yaml совместимо (с некоторыми простыми разрешимыми проблемами) со старым использованием PyYAML и, как указано в приведенной мной ссылке, используйте

from ruamel import yaml

вместо

import yaml

и это решит большинство ваших проблем.

РЕДАКТИРОВАТЬ : PyYAML не мертв, как оказалось, он просто поддерживается в другом месте.

Александр Зеленцов
источник
@ Александр: PyYaml имеет коммиты за последние 7 месяцев, а последний закрытый выпуск был 12 дней назад. Можете ли вы определить "давно умерших"?
abalter
@abalter Прошу прощения, похоже, что я получил информацию с их официального сайта или поста прямо здесь stackoverflow.com/a/36760452/5510526
Александр Зеленцов
@OleksandrZelentsov Я вижу замешательство. Был очень долгий период, когда он был мертв. github.com/yaml/pyyaml/graphs/contributors . Тем не менее, их сайт работает и показывает выпуски, опубликованные ПОСЛЕ ТАКОГО сообщения, связанного с кончиной PyYaml. Поэтому справедливо сказать, что на данный момент он все еще жив, хотя его направление относительно руамеля явно неопределенно. ТАКЖЕ, здесь были длинные обсуждения с последними сообщениями. Я добавил комментарий, и теперь мой единственный. Я думаю, я не понимаю, как работают закрытые вопросы. github.com/yaml/pyyaml/issues/145
abalter
@abalter FWIW, когда этот ответ был опубликован, в прошлом было совершено 9 коммитов ... чуть менее 7 лет. Одним из них было автоматическое «исправление» плохой грамматики. Двое участвовали в выпуске едва изменившейся новой версии. Остальные были относительно крошечными изменениями, в основном сделанными за пять лет до ответа. Все, кроме автоматического исправления, были сделаны одним человеком. Я бы не стал резко судить об этом ответе за то, что назвал PyYAML "давно умершим".
Фонд Моника иск
-1
#!/usr/bin/env python

import sys
import yaml

def main(argv):

    with open(argv[0]) as stream:
        try:
            #print(yaml.load(stream))
            return 0
        except yaml.YAMLError as exc:
            print(exc)
            return 1

if __name__ == "__main__":
    sys.exit(main(sys.argv[1:]))
Войцех Sciesinski
источник
1
Этот код на самом деле ничего не делает. Вы хотели закомментировать код?
Cowlinator