Yaml формат
# - комментарии
Ключ-значение
first: second
Обязательный пробел после :
Вложенные ресурсы в python виде, два пробела
Типы данных
Строка.Можно определять самим, можно отдавать на определение интерпретатору. Способ самостоятельного определения:
| Тип данных | Без определения типа | Пример с определением |
| строка |
myparam: 'first' myparam: first myparam: "first" Может быть без кавычек если хотя-бы один нечисловой символ |
!!str myparam: !!str 'first' |
| Многостроковая переменная: |
С сохранением переходов на новую строку:
config: > |
|
| целое число | 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:
3
Список словарей. |
!!seq myparam: !!seq [1, 2, 3] |
| словарь (отображение) |
myparam: {key: value} myparam: |
!!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: |
!!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
Перекрестные ссылки и якоря не работают между документами. Это полностью независимые документы.