Сообщить об ошибке.

Сохранение/сериализация различных типов Python в файл YAML

Функция yaml.dump() и yaml.dump_all() модуля PyYAML в Python

Для сериализации объекта Python в поток YAML необходимо использовать функцию yaml.dump(data, stream) модуля PyYAML.

Примечание: кроме того, можно использовать функцию yaml.safe_dump(data, stream), которая не поддерживает произвольные объекты Python. При использовании функции yaml.safe_dump() будут сгенерированы только стандартные теги YAML.

Смотрим простой пример преобразования словаря Python в поток YAML.

import yaml
# словарь Python
py_obj = {'name': 'Silenthand Olleander', 'race': 'Human', \
          'traits': ['ONE_HAND', 'ONE_EYE']}
# сериализуем `py_obj` в формат YAML
yml_doc = yaml.dump(py_obj)
# смотрим, что получилось
print(yml_doc)
# name: Silenthand Olleander
# race: Human
# traits:
# - ONE_HAND
# - ONE_EYE

Используя функцию yaml.dump(), можно переводить объекты Python в формат YAML и записывать их в файлы YAML, чтобы использовать в будущем. Этот процесс известен как сериализация YAML.

Функция yaml.dump(data, stream=None) принимает два аргумента:

Если указаны оба аргумента, то yaml.dump() запишет созданный документ YAML в файл, в противном случае функция возвращает созданный документ.

Пример записи/сериализации объекта Python в файл YAML.

import yaml
# словарь Python
user = {'UserName': 'Alice',
        'Password': 'star123*',
        'phone': 3256,
        'AccessKeys': ['EmployeeTable',
                       'SoftwaresList',
                       'HardwareList']}

# открываем файл на запись
with open('test.yaml', 'w') as fw:
    # сериализуем словарь `user` в формат YAML
    # и записываем все в файл `test.yaml`
    data = yaml.dump(user, fw, sort_keys=False, 
                     default_flow_style=False)

# смотрим, что получилось
with open('test.yaml', 'r') as fr:
    print(fr.read())

# UserName: Alice
# Password: star123*
# phone: 3256
# AccessKeys:
#  - EmployeeTable
#  - SoftwaresList
#  - HardwareList

Так же, функция yaml.dump(), принимает несколько ключевых аргументов:

  • default_flow_style=False: используется для отображения содержимого вложенных блоков с правильным отступом. По умолчанию, стиль отображения содержимого блока принимает правильный отступ. При значении default_flow_style=True, значения внутри вложенных элементов отображаются в стиле потока.
  • sort_keys=True: используется для сортировки ключей в алфавитном порядке. Значение по умолчанию True. Для сохранения оригинального порядка ключей словаря, используйте sort_keys=False.
  • explicit_start: создает начало документа YAML (добавляет в начало '---').
  • indent: чтобы установить предпочтительный отступ,
  • width: установка предпочтительной ширины,
  • canonical=True: устанавливает предпочтительный стиль для коллекций.

Форматирование документов YAML при сериализации.

При сериализации объектов Python в документ YAML можно указывать параметры форматирования, используя следующие ключевые аргументы: indent, width и canonical.

Примеры форматирования документов YAML при сериализации:

# форматирование списка
lst = list(range(50))
print(yaml.dump(lst, width=50, indent=4, default_flow_style=True))
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
    16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,
    28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
    40, 41, 42, 43, 44, 45, 46, 47, 48, 49]


# форматирование диапазона `range()`
print(yaml.dump(range(5), canonical=True))
# ---
# !!python/object/apply:builtins.range [
#   !!int "0",
#   !!int "5",
#   !!int "1",
# ]

print(yaml.dump(range(5), default_flow_style=False))
# !!python/object/apply:builtins.range
# - 0
# - 5
# - 1

print(yaml.dump(range(5), default_flow_style=True, default_style='"'))
# !!python/object/apply:builtins.range [!!int "0", !!int "5", !!int "1"]

Дамп нескольких документов YAML.

Если вам нужно сбросить несколько документов YAML в один поток, используйте функцию yaml.dump_all(). Функция yaml.dump_all(lst, fp) принимает список или генератор, производящий объекты Python для сериализации в документ YAML. Второй необязательный аргумент - открытый файл.

Смотрим как это работает на простом списке:

lst = [1, 2, 3]
# простой дамп
yml = yaml.dump(lst, explicit_start=True)
print(yml)
# ---
# - 1
# - 2
# - 3

# дамп с разделением по документам YAML
# обратите внимание, что у каждого значения 
# есть начало документа `---` 
yml = yaml.dump_all(lst, explicit_start=True)
print(yml)
# --- 1
# --- 2
# --- 3
# ...

Ну а если серьезно, то смотрим полный пример:

# допустим есть объекты
class Hero():
    def __init__(self, name, hp, sp):
        self.name = name
        self.hp = hp
        self.sp = sp

class Monster():
    def __init__(self, name, hp, attacks):
        self.name = name
        self.hp = hp
        self.attacks = attacks

lst = [1, 2, 3, 4, 5, 6, 7]

py_obj = {'name': 'Silenthand Olleander', 
          'race': 'Human',
          'traits': ['ONE_HAND', 'ONE_EYE']}
          
user = {'UserName': 'Alice',
        'Password': 'star123*',
        'phone': 3256,
        'AccessKeys': ['EmployeeTable',
                       'SoftwaresList',
                       'HardwareList']}

# определяем документы для сохранения в YAML
doc1 = {'lst': lst, 'py_obj': py_obj}
doc2 = {'user': user}
hero = Hero('Welthyr Syxgon', 1200, 0)
monster = Monster('Spider', 16, ['BITE', 'HURT'])
doc3 = {'hero': hero, 'monster': monster}
# объединяем документы в список для сериализации по разным документам
docs_yml = [doc1, doc2, doc3]
# дамп с разделением по документам YAML
yml = yaml.dump_all(docs_yml, explicit_start=True)
print(yml)
# ---
# lst:
#  - 1
#  - 2
#  - 3
#  - 4
#  - 5
#  - 6
#  - 7
# py_obj:
#   name: Silenthand Olleander
#   race: Human
#   traits:
#    - ONE_HAND
#    - ONE_EYE
# ---
# user:
#   AccessKeys:
#    - EmployeeTable
#    - SoftwaresList
#    - HardwareList
#   Password: star123*
#   UserName: Alice
#   phone: 3256
# ---
# hero: !!python/object:__main__.Hero
#   hp: 1200
#   name: Welthyr Syxgon
#   sp: 0
# monster: !!python/object:__main__.Monster
#   attacks:
#    - BITE
#    - HURT
#   hp: 16
#   name: Spider