۶ قابلیت YAML که اکثر برنامهنویسان از آنها بیاطلاع هستند
۲۴ بهمن ۱۳۹۹
YAML یک فرمت فایل است که معمولا برای data serialization استفاده میشود. همچنین پروژههای زیاد وجود دارند که از فایلهای YAML بهمنظور پیکربندی استفاده میکنند برای مثال میتوانیم به Docker-compose، pre-commit, TravisCI، AWS Cloudformation، ESLint، Kubernetes، Ansible اشاره داشته باشیم. بنابراین آشنایی با قابلیتهای YAML میتواند بسیار مفید باشد.
در ابتدا باید بدانید که YAML با توجه به این مقاله بسیاری قابلیتهای JSON را در خود دارد. هر فایل معتبر JSON نیز یک فایل معتبر YAML است. این یعنی شما تمام نوعهای متغیر مورد نیاز خود مانند integerها، floatها، stringها، booleanها، null و همچنین sequenceها و mapها را در اختیار دارید. به نسبت زبان برنامهنویسی که از آن استفاده میکنید ممکن است sequence را بهعنوان array یا list و از map بهعنوان dictionary استفاده کنید.
یک فایل YAML معمولا به شکل زیر است:
mysql:
host: localhost
user: root
password: something
preprocessing_queue: # Line comments are available!
- name: preprocessing.scale_and_center
width: 32
height: 32
- preprocessing.dot_reduction
use_anonymous: true
Equivalent Notation
برای پیادهسازی فایلهای YAML روشهای معادل زیادی وجود دارد:
list_by_dash:
- foo
- bar
list_by_square_bracets: [foo, bar]
map_by_indentation:
foo: bar
bar: baz
map_by_curly_braces: { foo: bar, bar: baz }
string_no_quotes: Monty Python
string_double_quotes: "Monty Python"
string_single_quotes: 'Monty Python'
bool_english: yes
bool_english_no: no
bool_python: True
bool_json: true
یکی از مواردی که باید به آن توجه داشته باشید:
language: no # ISO 639-1 code for the Norwegian language
این no بهمعنای false است و برای نوشتن no میتوانید آن را در double quotes یا single quotes بگذارید. البته بهطور کلی توصیه میشود که از true
و false
برای مقادیر boolean استفاده شود اما در YAML میتوانید به ۱۱ روش booleanها را مقداردهی کنید.
اگر میخواهید از quotes برای stringها استفاده کنید بهتر است از double quotes استفاده شود زیرا برای افراد تازهکاری که میخواهند با فایلهای YAML کار کنند قابل درکتر است.
البته معادلهای بسیار زیاد دیگری وجود دارد و همانطور که Tom Ritchford اشاره کرده است شاید این معادلهای بسیار زیاد باعث شود تا فایلهای YAML انتخابی خطرناک و نامناسب باشند.
Long Strings
disclaimer: >
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
In nec urna pellentesque, imperdiet urna vitae, hendrerit
odio. Donec porta aliquet laoreet. Sed viverra tempus fringilla.
YAML فوق معادل JSON زیر است:
{ "disclaimer": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. In nec urna pellentesque, imperdiet urna vitae, hendrerit odio. Donec porta aliquet laoreet. Sed viverra tempus fringilla." }
Multi-Line String
mail_signature: |
Martin Thoma
Tel. +49 123 4567
YAML فوق معادل JSON زیر است:
{ "mail_signature": "Martin Thoma\nTel. +49 123 4567" }
Anchor
email: &emailAddress "info@example.de"
id: *emailAddress
YAML فوق معادل JSON زیر است:
{
"email": "info@example.de",
"id": "info@example.de"
}
با استفاده از &
یک متغیر با نام emailAddress
و مقدار info@example.de
تعریف میشود و *emailAddress
به مقدار متغیر تعریف شده اشاره میکند.
شما میتوانید همین کار را با mapping انجام دهید:
foo: &default_settings
db:
host: localhost
name: main_db
port: 1337
email:
admin: admin@example.com
prod: *default_settings
dev: *default_settings
معادل:
{
"dev": {
"db": {
"host": "localhost",
"name": "main_db",
"port": 1337
},
"email": {
"admin": "admin@example.com"
}
},
"foo": {
"db": {
"host": "localhost",
"name": "main_db",
"port": 1337
},
"email": {
"admin": "admin@example.com"
}
},
"prod": {
"db": {
"host": "localhost",
"name": "main_db",
"port": 1337
},
"email": {
"admin": "admin@example.com"
}
}
}
ممکن است بخواهید که رمزعبور دیتابیس یا هر دادهی دیگری را به تنظیمات dev و prod اضافه کنید که با استفاده از merge key <<
میتوان این کار را انجام داد.
foo: &default_settings
db:
host: localhost
name: main_db
port: 1337
email:
admin: admin@example.com
prod:
<<: *default_settings
app:
port: 80
dev: *default_settings
YAML فوق معادل JSON زیر است:
{
"foo": {
"db": {
"host": "localhost",
"name": "main_db",
"port": 1337
},
"email": {
"admin": "admin@example.com"
}
},
"prod": {
"app": {
"port": 80
},
"db": {
"host": "localhost",
"name": "main_db",
"port": 1337
},
"email": {
"admin": "admin@example.com"
}
},
"dev": {
"db": {
"host": "localhost",
"name": "main_db",
"port": 1337
},
"email": {
"admin": "admin@example.com"
}
}
}
Type Casting
!!
در YAML معنای خاصی دارد و با توجه به این مستندات کوتاه شدهی !tag:yaml.org,2002:
است.
برای تبدیل نوع متغیر میتوانید بهصورت زیر عمل کنید:
price: !!float 42
id: !!str 42
یا در موارد پیچیدهتر میتوانیم دادهها را به انواع دادههایی که در زبان Python تعریف شدهاند اما در YAML بهصورت مستقیم وجود ندارند، تبدیل کنیم:
tuple_example: !!python/tuple
- 1337
- 42
set_example: !!set { 1337, 42 }
date_example: !!timestamp 2020-12-31
YAML فوق را میتوان معادلی برای کدهای زیر دانست:
import yaml
import pprint
with open("example.yaml") as fp:
data = fp.read()
pp = pprint.PrettyPrinter(indent=4)
pased = yaml.unsafe_load(data)
pp.pprint(pased)
که خروجی آن بهصورت زیر است:
{ 'date_example': datetime.date(2020, 12, 31),
'set_example': set([42, 1337]),
'tuple_example': (1337, 42)}
در این مثال از تگ مخصوص برای زبان Python یعنی !!python/tuple
و برخی تگهای استاندارد YAML استفاده شده است. PyYaml اطلاعات بیشتری در این باره ارائه میدهد:
## Standard YAML tags
YAML Python 3
!!null None
!!bool bool
!!int int
!!float float
!!binary bytes
!!timestamp datetime.datetime
!!omap, !!pairs list of pairs
!!set set
!!str str
!!seq list
!!map dict## Python-specific tags
YAML Python 3
!!python/none None
!!python/bool bool
!!python/bytes bytes
!!python/str str
!!python/unicode str
!!python/int int
!!python/long int
!!python/float float
!!python/complex complex
!!python/list list
!!python/tuple tuple
!!python/dict dict## Complex Python tags
!!python/name:module.name module.name
!!python/module:package.module package.module
!!python/object:module.cls module.cls instance
!!python/object/new:module.cls module.cls instance
!!python/object/apply:module.f value of f(...)
توجه داشته باشید که load کردن تگهای غیر استاندارد، ایمن نیست! اما بههرصورت اجرای کدهای دلخواه با !!python/object/apply:module.f
امکانپذیر است. در PyYaml به yaml.unsafe_load
نیاز است تا بتوانید از آن استفاده کنید.
Multiple Documents در یک فایل YAML
شما میتوانید با استفاده از سه -
داکیومنتهای جداگانهای داشته باشید:
foo: bar
---
fizz: buzz
در Python میتوانید بهصورت زیر عمل کنید:
import yaml
with open("example.yaml") as fp:
data = fp.read()
parsed = yaml.safe_load_all(data) # parsed is a generator
اگر متغیر parsed
را به list تبدیل کرده و آن را print کنید، خروجی به شکل زیر خواهد بود:
[{'foo': 'bar'}, {'fizz': 'buzz'}]
توجه داشته باشید که این یک معادل جایگزین برای ایجاد list نیست.
منبع: https://levelup.gitconnected.com/6-yaml-features-most-programmers-dont-know-164762343af3