Python實現解析yaml配置文件的示例詳解
楔子
前面我們介紹了 ini 格式的配置文件,本次來看看 yaml,它的表達能力相比 ini 更加的強大。yaml 文件以 .yml 結尾,在介紹它的語法結構之前我們先來看看 yaml 的一些基本規(guī)則。
- 大小寫敏感;
- 使用縮進表示層級關系,并且縮進只能用空格、不可以使用 tab 鍵。縮進的空格數目不重要,只要相同層級的元素左側對齊即可;
- # 表示注釋,# 到行尾的所有字符都會被忽略;
yaml 支持的數據結構有以下三種:
- 字典:鍵值對的集合;
- 數組:多個元素組成的集合;
- 標量:單個、不可分割的值;
Python 解析 yaml 則是通過一個名為 pyyaml 的庫,直接 pip install pyyaml 即可。
下面我們來介紹一下 yaml 的數據結構。
字典
類似于 Python 的字典,使用鍵值對表示:
name:?satori
#?或者寫成下面的形式
{name:?satori}Python 解析之后會是什么結果呢?
import?yaml
config?=?"""
name:?satori
"""
# yaml.safe_load:只解析自己信任的輸入
# yaml.unsafe_load:不檢測輸入的安全性
print(yaml.safe_load(config))
"""
{'name':?'satori'}
"""
config?=?"""
{name:?satori}
"""
print(yaml.safe_load(config))
"""
{'name':?'satori'}
"""在 yaml 里面,字典的 value 也可以是一個字典:
info:?{name:?satori,?address:?東方地靈殿}Python 解析的結果如下:
import?yaml
config?=?"""
info:?{name:?satori,?address:?東方地靈殿}
"""
print(yaml.safe_load(config))
"""
{
??'info':?{'name':?'satori',?
???????????'address':?'東方地靈殿'}
}
"""還是很簡單的。
數組
一組連字符開頭的行,構成一個數組。
-?古明地覺 -?古明地戀 -?霧雨魔理沙 #?-?后面要有空格 #?或者寫成下面的形式 [古明地覺,?古明地戀,?霧雨魔理沙]
Python 解析的結果如下:
import?yaml config?=?""" -?古明地覺 -?古明地戀 -?霧雨魔理沙 """ print(yaml.safe_load(config)) """ ['古明地覺',?'古明地戀',?'霧雨魔理沙'] """ config?=?""" [古明地覺,?古明地戀,?霧雨魔理沙] """ print(yaml.safe_load(config)) """ ['古明地覺',?'古明地戀',?'霧雨魔理沙'] """
并且數組的子成員也可以是一個數組:
-
- 古明地覺
- 古明地戀
- 霧雨魔理沙
Python 解析的結果如下:
import?yaml config?=?""" - ??-?古明地覺 ??-?古明地戀 ??-?霧雨魔理沙 """ print(yaml.safe_load(config)) """ [['古明地覺',?'古明地戀',?'霧雨魔理沙']] """ #?更簡潔的寫法 config?=?""" -?[古明地覺,?古明地戀,?霧雨魔理沙] """ print(yaml.safe_load(config)) """ [['古明地覺',?'古明地戀',?'霧雨魔理沙']] """
顯然數組也可以放在字典中:
#?縮進對應的空格數沒有要求,但是必須一樣
#?對于當前這個鍵值對而言也可以沒有縮進
girl:
????-?古明地覺
????-?古明地戀
????-?霧雨魔理沙
#?或者下面這種形式
girl:?[古明地覺,?古明地戀,?霧雨魔理沙]
#?或者下面這種形式
{girl:?[古明地覺,?古明地戀,?霧雨魔理沙]}Python 解析的結果如下:
import?yaml
config?=?"""
girl:
??-?古明地覺
??-?古明地戀
??-?霧雨魔理沙
"""
print(yaml.safe_load(config))
"""
{'girl':?['古明地覺',?'古明地戀',?'霧雨魔理沙']}
"""
#?注意:上面的 girl 對應的是數組
#?因為每個元素前面都有?-
#?但如果沒有的話會發(fā)生什么?
config?=?"""
girl:
????古明地覺
????古明地戀
????霧雨魔理沙
"""
print(yaml.safe_load(config))
"""
{'girl':?'古明地覺?古明地戀?霧雨魔理沙'}
"""
#?我們看到整體相當于是一個字符串
#?類似于?html,之間用一個空格代替
#?因此如果內容比較長,我們可以寫成多行
#?但是注意:每一行前面必須有空格然后是一個稍微復雜的例子:
import?yaml
config?=?"""
girl:
????#?會對應一個數組
????-?古明地覺
????-?古明地戀
????-?霧雨魔理沙
????
place1:
????#?雖然不是數組,但是內部是字典的形式
????#?所以會對應一個含有三個鍵值對的字典
????古明地覺:?東方地靈殿
????古明地戀:?東方地靈殿
????霧雨魔理沙:?魔法森林
place2:
??#?是數組,數組里面每個元素是一個字典
??-?古明地覺:?東方地靈殿
??-?古明地戀:?東方地靈殿
??-?霧雨魔理沙:?魔法森林
"""
print(yaml.safe_load(config))
"""
{
????'girl':?['古明地覺',?'古明地戀',?'霧雨魔理沙'],
????'place1':?{'古明地覺':?'東方地靈殿',?
???????????????'古明地戀':?'東方地靈殿',?
???????????????'霧雨魔理沙':?'魔法森林'},
????'place2':?[{'古明地覺':?'東方地靈殿'},?
???????????????{'古明地戀':?'東方地靈殿'},?
???????????????{'霧雨魔理沙':?'魔法森林'}]
}
"""place1 對應的是一個字典,place2 對應的是一個數組。
標量
標量屬于最基本的、不可再分的值,比較簡單,我們就全部都說了吧。
import?yaml
config?=?"""
int:?123
float:?3.14
bool:
????-?true?
????-?false
#?波浪號表示空????
NoneType:?~??
datetime:?2020-11-11?12:12:13
#?使用兩個?!?可以進行類型強轉
#?不過幾乎用不到?
cast:
????-?!!str?123
????-?!!str?true??
"""
print(yaml.safe_load(config))
"""
{
????'int':?123,?'float':?3.14,
????'bool':?[True,?False],?'NoneType':?None,
????'datetime':?datetime.datetime(2020,?11,?11,?12,?12,?13),?
????'cast':?['123',?'true']
}
"""這里可能有人已經發(fā)現了,就是字符串不需要加引號,但如果里面有特殊字符怎么辦?所以 yaml 是支持使用引號括起來的。
import?yaml
config?=?"""
name1:?古明地覺??????a?x???$?#??!!????????
name2:?"古明地覺??????a?x???$?#??!!"????????
name3:?'古明地覺??????a?x???$?#??!!'???
"""
print(yaml.safe_load(config))
"""
{'name1':?'古明地覺??????a?x???$',?
?'name2':?'古明地覺??????a?x???$?#??!!',?
?'name3':?'古明地覺??????a?x???$?#??!!'}
"""對于 yaml 而言,字符串默認是從第一個不是空格的字符、匹配到最后一個不是空格的字符(如果遇到 # 直接停止)。因此如果 value 的前面或后面有空格的話,那么這些空格是不會顯示的,或者當中有 #,那么 # 后面的內容也不會顯示。
解決辦法是使用單引號或雙引號括起來,如果內部還有引號,那么需要輸入兩遍進行轉義(如果內部的引號和外面括起來的引號相同的話)。
引用
對于 yaml 而言,還支持我們采用 & 和 * 進行引用,舉個例子:
import?yaml
config?=?"""
#?多了一個?&db_info_ref
#?相當于起了個名字,叫?db_info_ref
db_info:?&db_info_ref??
????host:?127.0.0.1
????port:?5432
????user:?postgres
????password:?123456
deploy:
????os:?Linux
????#?將內容直接扔到里面來??
????<<:?*db_info_ref??
"""
print(yaml.safe_load(config))
"""
{
????'db_info':?{'host':?'127.0.0.1',
????????????????'port':?5432,
????????????????'user':?'postgres',
????????????????'password':?123456},
????'deploy':?{'host':?'127.0.0.1',
???????????????'port':?5432,
???????????????'user':?'postgres',
???????????????'password':?123456,
???????????????'os':?'Linux'}
}
"""& 用來建立錨點,<< 表示合并當前數據,* 表示用來引用錨點。還可以作用在數組中:
import?yaml config?=?""" -?&name?古明地覺? -?古明地戀 -?霧雨魔理沙 -?*name """ print(yaml.safe_load(config)) """ ['古明地覺',?'古明地戀',? ?'霧雨魔理沙',?'古明地覺'] """
生成 yaml 文件
既然能夠讀取 yaml 文件,那么自然也能生成 yaml 文件。
import?yaml
data?=?{
????"girl":?[
????????{"name":?"古明地覺",?"age":?17,?"place":?"東方地靈殿"},
????????{"name":?"古明地戀",?"age":?16,?"place":?"東方地靈殿"},
????????{"name":?"霧雨魔理沙",?"age":?16,?"place":?"魔法森林"}
????],
????"other":?{
????????"古明地覺":?{"nickname":?["小五",?"少女覺",?"覺大人",?"小五蘿莉"],
?????????????????"length":?155},
????????"古明地戀":?{"nickname":?["戀戀"],?"length":?155},
????????"霧雨魔理沙":?{"nickname":?["摸你傻"],?"length":?155}
????}
}
with?open("cfg.yml",?"w",?encoding="utf-8")?as?f:
????yaml.dump(data,?f,?allow_unicode=True,?indent=2)然后我們看看生成的 yml 文件長什么樣子。

我們來看 yml 文件,然后反推出相應的數據結構。首先整體是一個字典,里面有 girl 和 other 兩個 key。其中 girl 對應一個數組,數組里面每個元素都是字典,這是符合預期的。
然后 other 對應一個字典,而且這個字典內部有三個鍵值對,key 分別是:古明地覺、古明地戀、霧雨魔理沙,各自對應的 value 又是一個字典(內部有 length、nickname 兩個 key,length 對應整型、nickname 對應列表)。
最后再看一個本人之前項目中的 yml 文件,可以猜猜看解析出來長什么樣子。

解析一下看看和你想的是不是一樣的。
import?yaml
with?open(".gitlab-ci.yml",?"r",?encoding="utf-8")?as?f:
????data?=?f.read()
data?=?yaml.safe_load(data)
print(data)
"""
{
????'stages':?['test'],?
????'cache':?{'key':?'${CI_COMMIT_REF_SLUG}',?
??????????????'paths':?['.cache/pip']},
????'variables':?{'PIP_CACHE_DIR':?'$CI_PROJECT_DIR/.cache/pip'},
????'test':?{'stage':?'test',?
?????????????'image':?'xxxxxxx/python:3.8.1-thanosclient-buster',?
?????????????'only':?['branches',?'tags'],
?????????????'services':?['mysql:5.7'],
?????????????'variables':?{'PROJECT':?'XXXXXX',?
???????????????????????????'PIP_CACHE_DIR':?'$CI_PROJECT_DIR/.cache/pip',
???????????????????????????'MARKETING_CONFIG':?'config/room/ci.cn-gz.toml',
???????????????????????????'MYSQL_DATABASE':?'activity',?
???????????????????????????'MYSQL_ROOT_PASSWORD':?'password',
???????????????????????????'MYSQL_INITDB_SKIP_TZINFO':?'1'}
?????????????}
}
"""結果應該不難想,畢竟 yaml 文件不是很復雜。
以上就是Python實現解析yaml配置文件的示例詳解的詳細內容,更多關于Python解析yaml配置文件的資料請關注腳本之家其它相關文章!
相關文章
可用于監(jiān)控 mysql Master Slave 狀態(tài)的python代碼
用于監(jiān)控MySQL Master Slave 狀態(tài)的python代碼,有需要的朋友可以參考下2013-02-02

