亚洲熟女综合色一区二区三区,亚洲精品中文字幕无码蜜桃,亚洲va欧美va日韩va成人网,亚洲av无码国产一区二区三区,亚洲精品无码久久久久久久

很實用的 PyYAML 使用技巧

YAML 是一個被廣泛使用的數(shù)據(jù)序列化和配置語言,作為一個開發(fā)者,總是不免和它打交道。但處理 YAML 文檔,尤其是使用 PyYAML 的過程總是非常痛苦。

這篇文章分享我在 Python 下使用 PyYAML 的技巧和代碼片段,并介紹幾個相關(guān)的庫。

注意:本文中的代碼僅保證在 Python 3 下正常工作

總是使用?safe_load/safe_dump

PyYAML 的?load?函數(shù)可以構(gòu)造任意 Python 對象(Pickle 協(xié)議),這意味著一次?load?可能導(dǎo)致任意 Python 函數(shù)被執(zhí)行。

為了確保應(yīng)用程序的安全性,盡量在任何情況下使用?yaml.safe_load?和?yaml.safe_dump。

保留字段順序

Python 3.7+ 中,dict?keys 具備保留插入順序的特性,所以通過?yaml.safe_load?得到的?dict,其 keys 順序會與原始文件保持一致。

>>>?import?yaml
>>>?text?=?"""---
...?c:?1
...?b:?1
...?d:?1
...?a:?1
...?"""
>>>?d?=?yaml.safe_load(text)
>>>?d
{'c':?1,?'b':?1,?'d':?1,?'a':?1}
>>>?list(d)
['c',?'b',?'d',?'a']

當(dāng)把?dict?導(dǎo)出為 YAML 字符串時,為?yaml.safe_dump?傳遞?sort_keys=False?來保留 keys 的順序。

>>>?print(yaml.safe_dump(d))
a:?1
b:?1
c:?1
d:?1
>>>?d['e']?=?1
>>>?print(yaml.safe_dump(d,?sort_keys=False))
c:?1
b:?1
d:?1
a:?1
e:?1

如果 Python 版本較低,或者你想確保代碼能在更廣泛的環(huán)境下工作,你可以使用?oyaml?庫來代替 PyYAML 的?yaml?包。

>>>?import?oyaml?as?yaml
>>>?d?=?yaml.safe_load(text)
>>>?d
OrderedDict([('c',?1),?('b',?1),?('d',?1),?('a',?1)])
>>>?d['e']?=?1
>>>?print(yaml.safe_dump(d,?sort_keys=False))
c:?1
b:?1
d:?1
a:?1
e:?1

優(yōu)化列表項的縮進

默認情況下,PyYAML 輸出的列表縮進與其父元素一致。

>>>?d?=?{'a':?[1,?2,?3]}
>>>?print(yaml.safe_dump(d))
a:
-?1
-?2
-?3

這并不是很好的格式,根據(jù) Ansible 和 HomeAssistant 等 YAML 書寫規(guī)范,列表項應(yīng)該縮進 2 空格。

這種格式也會對導(dǎo)致列表項不會被如 VSCode 等編輯器識別,進而無法使用編輯器的折疊功能。

要解決這個問題,使用如下代碼片段,在代碼中定義?IndentDumper?class:

class?IndentDumper(yaml.Dumper):
????def?increase_indent(self,?flow=False,?indentless=False):
????????return?super(IndentDumper,?self).increase_indent(flow,?False)

然后將它傳遞給?yaml.dump?的?Dumper?關(guān)鍵字參數(shù)。

>>>?print(yaml.dump(d,?Dumper=IndentDumper))
a:
??-?1
??-?2
??-?3

注意,yaml.safe_dump?由于有自己的 Dumper class,傳遞此參數(shù)會造成沖突。

輸出可讀的 UTF-8 字符

默認情況下,PyYAML 假設(shè)你希望輸出的結(jié)果里只有 ASCII 字符。

>>>?d?=?{'a':?'你好'}
>>>?print(yaml.safe_dump(d))
a:?"\u4F60\u597D"

這會讓輸出結(jié)果非常難以閱讀。

在 UTF-8 足夠普及的今天,直接輸出 UTF-8 字符是非常安全的。因此我們可以將?allow_unicode=True?傳入?yaml.safe_dump?使 PyYAML 將 Unicode 轉(zhuǎn)換成 UTF-8 字符串。

>>>?print(yaml.safe_dump(d,?allow_unicode=True))
a:?你好

一些 YAML 相關(guān)的庫

oyaml

Link:?https://github.com/wimglenn/oyaml

正如上文中提到的,oyaml 是?yaml?包的替換品,使?dict?keys 的順序在 dump/load 的時候得以保留。

oyaml 是一個單文件庫,只有 53 行代碼,因此使用起來非常靈活,你可以直接把它的代碼復(fù)制到自己的項目中,然后根據(jù)自己的需求進行修改。

strictyaml

Link:?https://github.com/crdoconnor/strictyaml

有的人說 YAML 過于復(fù)雜和靈活,不是一個好的配置語言。但我認為這不是 YAML 的問題,而是使用方式的問題。如果我們限制程序只使用 YAML 的部分功能,YAML 其實可以變得像它設(shè)計的那般好用。

這就是 StrictYAML 的設(shè)計意圖,它是一個類型安全的 YAML 解析器,實現(xiàn)了 YAML 規(guī)范說明中的一個子集?。

如果你對 YAML 的輸入輸出有較強的安全考慮,建議使用 StrictYAML 代替 PyYAML。

順帶一提的是,StrictYAML 的文檔站有很多關(guān)于設(shè)計細節(jié)和配置語言思考的文章,非常值得一看。

ruamel.yaml

Link:?https://yaml.readthedocs.io/en/latest/overview.html

ruamel.yaml 是 PyYAML 的一個分叉,于 2009 年發(fā)布并持續(xù)維護至今。

ruamel.yaml 的文檔里詳細說明了它和 PyYAML 的差異??傮w來說,ruamel.yaml 專注在 YAML 1.2 上,對一些語法進行了優(yōu)化。

ruamel.yaml 最令我感興趣的特性是輸入輸出的 “round-trip”,可以最大程度地保留輸入源的原始格式。官方文檔中的定義是這樣的:

A round-trip is a YAML load-modify-save sequence and ruamel.yaml tries to preserve, among others:

  • comments
  • block style and key ordering are kept, so you can diff the round-tripped source
  • flow style sequences ( ‘a(chǎn): b, c, d’) (based on request and test by Anthony Sottile)
  • anchor names that are hand-crafted (i.e. not of the formidNNN)
  • merges?in dictionaries are preserved

如果你有盡可能保留原始格式的需求,建議使用 ruamel.yaml 代替 PyYAML。

在使用中我注意到 ruamel.yaml 的 safe load 方法 (YAML(typ='safe').load) 與 PyYAML 有些不同,它無法解析 flow style 的集合定義 (如?a: {"foo": "bar"}),這點沒有在文檔中提及,使用時須多加注意。

總結(jié)

YAML 有它好的地方和壞的地方。它易于閱讀,初期的學(xué)習(xí)曲線非常平緩。但 YAML 的規(guī)范說明非常復(fù)雜,不僅造成了使用中的混亂,也使不同語言的實現(xiàn)在很多細微的地方難以保持一致。

盡管有這些小毛病,YAML 仍然是我心中最好的配置語言。希望這篇文章所介紹的技巧能夠幫助你避免問題,獲得更好的開發(fā)和使用體驗。

鏈接:https://reorx.com/blog/python-yaml-tips-zh/

(版權(quán)歸原作者所有,侵刪)

相關(guān)新聞

歷經(jīng)多年發(fā)展,已成為國內(nèi)好評如潮的Linux云計算運維、SRE、Devops、網(wǎng)絡(luò)安全、云原生、Go、Python開發(fā)專業(yè)人才培訓(xùn)機構(gòu)!