Як я можу розібрати YAML-файл у Python


Відповіді:


806

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

#!/usr/bin/env python

import yaml

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
Ямл ямл = новий Ямл (); Об'єкт 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

61

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

Якщо ви хочете зберегти свої коментарі під час кругового відключення, вам неодмінно слід використовувати ruamel.yaml.

Оновити приклад Джона легко:

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)

Привіт @Anthon Я використовував ruamel's, але у мене виникла проблема з документами, які не відповідають стандартам ( UnicodeDecodeError: 'ascii' codec can't decode byte 0xe7 in position 926: ordinal not in range(128)). Я намагався встановити yaml.encoding на utf-8, але не працював, оскільки метод навантаження в YAML все ще використовує код ascii_de. Це помилка?
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
Якщо у вашому файлі є рядок "- привіт, світ", мінливий 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

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

EDIT : PyYAML не мертвий, як виявляється, він просто підтримується в іншому місці.


@Oleksander: PyYaml взяв на себе зобов'язання протягом останніх 7 місяців, а останній закритий випуск був 12 днів тому. Ви можете, будь ласка, визначити "давно померлих?"
абальтер

@abalter Вибачаюсь, здається, що я отримав інформацію з їх офіційного сайту чи публікації тут stackoverflow.com/a/36760452/5510526
Олександр Зеленцов

@OleksandrZelentsov Я бачу плутанину. Був довгий період, коли він був мертвий. github.com/yaml/pyyaml/graphs/contributors . Однак їхній сайт розгорнувся і показує випуски, розміщені ПІСЛЯ посту ТА, що посилаються на смерть PyYaml. Тому справедливо сказати, що на даний момент він ще живий, хоча напрямок щодо руамеля явно не визначений. ТАКОЖ, тут тривали тривалі дискусії з останніми повідомленнями. Я додав коментар, і тепер мій єдиний. Я думаю, я не розумію, як працюють закриті проблеми. github.com/yaml/pyyaml/isissue/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:]))

1
Цей код насправді нічого не робить. Ви хотіли прокоментувати код?
ковбасник
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.