大多數程序員都不知道的6個YAML功能
提升您的YAML知識以編寫更清晰的YAML文件

YAML是一種常用于數據序列化的文件格式。有大量使用YAML文件進行配置的項目,例如Docker-compose,pre-commit,TravisCI,AWS Cloudformation,ESLint,Kubernetes,Ansible等。了解YAML的功能可以幫助您實現所有這些功能。
讓我們先介紹一下基礎知識:YAML是JSON(源)的超集。每個有效的JSON文件也是一個有效的YAML文件。這意味著您擁有所有期望的類型:整數,浮點數,字符串,布爾值,空值。以及序列和圖。根據您的編程語言,您可能說“ array”或“ list”而不是序列,而說“ dictionary”而不是map。
通常看起來像這樣:
- 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
等效符號
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
此否被解釋為false。您需要輸入“ no”或“ no”。
通常,我建議像布爾值JSON一樣使用true和false,但是YAML支持11種寫布爾值的方法。如果您想對字符串使用引號,我也將像JSON一樣使用“。您仍然需要記住” no“,但是至少該文件看起來對YAML初學者更熟悉。
正如湯姆·里奇福德(Tom Ritchford)所指出的,還有更多類似的危險案例:
- 013映射到11,因為前導零觸發八進制表示法
- 4:30映射到270。Max Werner Kaul-Gothe和Niklas Baumstark告訴我,這被自動轉換為分鐘(或秒?),因為它被解釋為持續時間:4 * 60 + 30 = 270。有趣的是,這種模式仍然可以在1:1:1:1:1:1:1:1:4:30的情況下“工作”。
長字符串
- 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.
這等效于以下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."}
多行字符串
- mail_signature: |
- Martin Thoma
- Tel. +49 123 4567
這等效于JSON:
{"mail_signature": "Martin Thoma\nTel. +49 123 4567"}
請注意如何忽略前導空格。第一行(“ Martin Thoma”)確定忽略的前導空白的數量。
錨
- email: &emailAddress "info@example.de"
- id: *emailAddress
這等效于以下JSON:
{"email": "info@example.de", "id": "info@example.de"}
&定義了一個變量emailAddress,其值為“ info@example.de。然后,*表示緊隨其后的是變量名。
您可以對映射執行相同的操作:
- 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"}}}
現在,您可能想在開發和生產設置中插入密碼。您可以使用合并鍵<<來做到這一點:
- 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
等效于以下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"}},}
類型轉化
雙重爆炸!在YAML中有特殊含義。它被稱為“第二標簽句柄”和!tag:yaml.org,2002 :(源)的簡寫。
您可以像這樣進行簡單的轉換:
- price: !!float 42
- id: !!str 42
或更復雜的內容,例如映射到直接在YAML中未指定的默認Python類型:
- tuple_example: !!python/tuple
- - 1337
- - 42
- set_example: !!set {1337, 42}
- date_example: !!timestamp 2020-12-31
您可以這樣閱讀:
- 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': {1337, 42},
- '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(...)
請注意,加載非標準標簽是不安全的!可以使用!! python / object / apply:module.f執行任意代碼。在PyYaml中,您需要yaml.unsafe_load才能使用它。因此,您可能不應該使用它!
一個YAML中的多個文檔
YAML中的三個破折號分別表示文檔:
- foo: bar
- ---
- fizz: buzz
在Python中,您可以使用PyYAML像這樣加載它:
- import yaml
- with open("example.yaml") as fp:
- data = fp.read()
- parsed = yaml.safe_load_all(data) # parsed is a generator
如果將已分析的內容轉換為列表并打印出來,則會得到:
- [{'foo': 'bar'}, {'fizz': 'buzz'}]
請注意,這不是寫列表的替代符號。是不同的文件。
靜態站點生成器Pelican使用它來區分元數據和內容。我還沒有看到其他任何使用此功能的應用程序。編輯:Clemens Tolboom提醒我,靜態網站生成器Jekyl也使用它。Chairat Onyaem(Par)指出oc進程也會生成此類YAML。謝謝你的評論!
下一步是什么?
有很多配置文件格式,例如TOML,INI,JSON,XML,dotenv,以及數據序列化格式,例如Pythons pickle,HDF5,Numpys NPZ,XML。如果您有興趣了解其中一個的更多信息,請告訴我!