Skip to main content

Yaml формат

# - комментарии

Ключ-значение 

first: second

Обязательный пробел после :

Вложенные ресурсы в python виде, два пробела

Типы данных

Строка.Можно определять самим, можно отдавать на определение интерпретатору. Способ самостоятельного определения: 

Тип данныхБез определения типаПример с определением
строка

myparam: 'first'

myparam: first

myparam: "first"

Может быть без кавычек если хотя-бы один нечисловой символ



!!str

myparam: !!str 'first'

Многостроковая переменная:

С сохранением переходов на новую строку:

config: |
  server.port=8443
  logfile=/var/log

ЧислаБез сохранения:

config: >
  server.port=8443
  logfile=/var/log


целое числоmyparam: 42

!!int

myparam: !!int 42

число с плавающей точкойmyparam: 3.14

!!float

myparam: !!float 3.14

булев типmyparam: true (или false, True, False, yes, no, on, off)

!!bool

myparam: !!bool true

пустое значениеmyparam: null (или ~, пустая строка myparam:)

!!null

myparam: !!null null

последовательность (список)

myparam: [1, 2, 3] 

myparam:
  - как1
 числа

Логические true/false

Список: 

ports: - 80802
  - 8443
3

Список словарей. 

env:
  - name: FIRSTVAR
    value: ONE
  - name: SECONDVAR
    value: TWO

!!seq

myparam: !!seq [1, 2, 3]

словарь (отображение)

myparam: {key: value} 

myparam:
  key: value

!!map

myparam: !!map {key: value}

дата и время

myparam: 2024-01-15T14:30:00Z

myparam: 2024-01-15 14:30:00

!!timestamp

myparam: !!timestamp 2024-01-15T14:30:00Z

двоичные данные (base64)myparam: R0lGODlh... (YAML автоматически не распознает, лучше явно указывать !!binary)

!!binary

myparam: !!binary R0lGODlh...

множествоВ явном виде без !!set не поддерживается — нужно использовать список с уникальностью вне YAML.

!!set

myparam: !!set {a, b, c}

упорядоченная карта

Без !!omap будет обычным словарём. Для порядка используют список пар:

myparam:
  - a: 1
  - b: 2

!!omap

myparam: !!omap [{a: 1}, {b: 2}]

список пар ключ-значениеБез !!pairs — обычный список с одним элементом-словарём.

!!pairs

myparam: !!pairs [key1: val1, key2: val2]

слияние картБез !!merge не работает — ключ << интерпретируется как обычная строка.

!!merge

myparam: !!merge <<: *defaults

Есть типы данных python. Работают только в Python-парсерах YAML (PyYAML, ruamel.yaml) и не являются частью стандарта YAML 1.1/1.2. Использование в других языках приведёт к ошибкам или игнорированию:

Тип данныхПример с определением
строка

!!python/str

myparam: !!python/str 'hello'

юникод-строка

!!python/unicode

myparam: !!python/unicode 'привет'

байтовая строка

!!python/bytes

myparam: !!python/bytes 'hello' (в base64)

целое число

!!python/int

myparam: !!python/int 12345678901234567890

!!python/long длинное целое (устар.)

myparam: !!python/long 42L

число с плавающей точкой

!!python/float

myparam: !!python/float 3.14

комплексное число 

!!python/complex

myparam: !!python/complex 2+3j

булев тип

!!python/bool

myparam: !!python/bool True

пустое значение

!!python/none

myparam: !!python/none None

последовательность (список)

!!python/list

myparam: !!python/list [1, 2, 3]

кортеж

!!python/tuple

myparam: !!python/tuple (1, 2, 3) (в YAML запись: !!python/tuple [1, 2, 3])

словарь (отображение)

!!python/dict

myparam: !!python/dict {a: 1, b: 2}

множество

!!python/set

myparam: !!python/set {1, 2, 3} (в YAML: !!python/set [1, 2, 3])

произвольный объект класса

!!python/object

myparam: !!python/object:module.Class {attr: value}

создание объекта через конструктор

!!python/object/new

myparam: !!python/object/new:module.Class [arg1, arg2]

вызов функции/конструктора

!!python/object/apply

myparam: !!python/object/apply:module.func [arg1, arg2]

ссылка на имя объекта

!!python/name

myparam: !!python/name:module.func

ссылка на модуль

!!python/module

myparam: !!python/module:math

объект-строка

!!python/object/str

myparam: !!python/object/str 'hello'

объект-список

!!python/object/list

myparam: !!python/object/list [1, 2, 3]

Пример кода: 

import yaml

# ВНИМАНИЕ: Этот код потенциально опасен!

yaml_str = """
functions:
  - !!python/name:builtins.print 
    args: ["Hello from YAML!"]
  - !!python/name:__main__.my_custom_func
    args: [10, 20]
"""

def my_custom_func(x, y):
    return f"Custom result: {x * y}"

# Используем unsafe_load для поддержки !!python/name
data = yaml.unsafe_load(yaml_str)

for func in data['functions']:
    # func здесь - это объект функции
    args = func.get('args', []) if isinstance(func, dict) else []
    
    if callable(func):
        result = func(*args)
        print(f"Результат: {result}")

Однако использование python/... как я понял считается опасным. Лучше без этого.

Переменные

Есть подходы по повторному использованию значений, в классическом понимании переменных нет (да и это не нужно). Определение переменных. 

# Определение якоря
defaults_something: &defaults
  timeout: 30
  retries: 3
  debug: false

# Использование алиаса
service1:
  <<: *defaults
  name: "service1"
  port: 8080

service2:
  <<: *defaults
  name: "service2"
  timeout: 60  # переопределяет значение из defaults
  port: 8081

# Пример с отдельными значениями
database: &db_config
  host: localhost
  port: 5432

development:
  database: *db_config
# в этом случае
developmen:
  database:
    host: localhost
    port: 5432

#Вложенное слияние
db_defaults: &db_defaults
  host: localhost
  port: 5432
  settings:
    pool_size: 10
    timeout: 30

production:
  database:
    <<: *db_defaults
    host: prod-db.com
    settings:
      <<: *db_defaults['settings']  # так нельзя
      # правильный способ:
      pool_size: 20
  • Merge key (<<) работает только со словарями (maps)
  • Порядок важен: переопределения должны идти после <<
  • Не все парсеры YAML поддерживают << (стандарт YAML 1.2 его исключил, но большинство парсеров поддерживают)
  • Алиасы (*name) и якоря (&name) работают везде

Множественные документы

Возможность хранить несколько независимых YAML-документов в одном файле, разделяя их тремя дефисами ---. Пример загрузки файла настроек с множественными документами:

import yaml

# Строка с несколькими документами
yaml_str = """
name: John
age: 30
---
users:
  - Alice
  - Bob
---
status: success
code: 200
"""

# Загрузка всех документов
documents = list(yaml.safe_load_all(yaml_str))

print(f"Загружено документов: {len(documents)}")
print(documents[0])  # {'name': 'John', 'age': 30}
print(documents[1])  # {'users': ['Alice', 'Bob']}
print(documents[2])  # {'status': 'success', 'code': 200}

Пример: конфигурация различных окружений 

# Документ 1: Общие настройки
environment: common
database:
  host: localhost
  port: 5432
---
# Документ 2: Настройки разработки
environment: development
debug: true
database:
  host: dev-db.local
---
# Документ 3: Продакшн настройки
environment: production
debug: false
database:
  host: prod-db.example.com
  pool_size: 20
import yaml

def load_env_config(env_name):
    with open('config.yaml', 'r') as file:
        for doc in yaml.safe_load_all(file):
            if doc and doc.get('environment') == env_name:
                return doc
    return None

dev_config = load_env_config('development')
prod_config = load_env_config('production')

print(dev_config['debug'])   # True
print(prod_config['debug'])  # False

Перекрестные ссылки и якоря не работают между документами. Это полностью независимые документы.