年輕人的狀態(tài)
有多少人和這張圖一樣,每天清晨起床時(shí)阳藻,都后悔昨晚不該熬夜晰奖,決定以后晚上早點(diǎn)睡覺(jué)。結(jié)果到了晚上腥泥,照樣一副 欲上九天攬?jiān)仑夷希滤暮W谨M的精神面貌...
可轉(zhuǎn)眼一想,如果我不熬夜蛔外,就得不到習(xí)大大的關(guān)懷蛆楞,辣怎么行?接著熬夜寫(xiě)文章吧夹厌!
pythonic的標(biāo)記語(yǔ)言
之前總結(jié)過(guò)一篇關(guān)于小數(shù)據(jù)存儲(chǔ)文件大比拼豹爹,當(dāng)時(shí)著重介紹了json,因?yàn)樗诟黝?lèi)編程語(yǔ)言的通用性較強(qiáng)矛纹。但今天臂聋,我想給大家介紹一款更加適合pythoner使用的語(yǔ)言Yaml。
YAML是一個(gè)可讀性高或南,用來(lái)表達(dá)數(shù)據(jù)序列化的格式逻住。YAML 是專(zhuān)門(mén)用來(lái)寫(xiě)配置文件的語(yǔ)言,非常簡(jiǎn)潔和強(qiáng)大迎献,遠(yuǎn)比 JSON 格式方便瞎访。
YAML是"YAML Ain't a Markup Language"(YAML不是一種標(biāo)記語(yǔ)言)的遞歸縮寫(xiě)。在開(kāi)發(fā)的這種語(yǔ)言時(shí)吁恍,YAML 的意思其實(shí)是:"Yet Another Markup Language"(仍是一種標(biāo)記語(yǔ)言)扒秸,但為了強(qiáng)調(diào)這種語(yǔ)言以數(shù)據(jù)做為中心,而不是以標(biāo)記語(yǔ)言為重點(diǎn)冀瓦,而用反向縮略語(yǔ)重命名伴奥。
之所以說(shuō)它更適合pythoner使用,是因?yàn)閅aml在很多方面都與python語(yǔ)言神似翼闽。
特點(diǎn) | Yaml | Python |
---|---|---|
使用#進(jìn)行注釋 | 是 | 是 |
區(qū)分大小寫(xiě) | 是 | 是 |
大小寫(xiě)敏感 | 是 | 是 |
使用縮進(jìn)表示層級(jí)關(guān)系 | 是 | 是 |
縮進(jìn)格式 | 使用空格鍵縮進(jìn)拾徙,而非Tab鍵縮進(jìn)。 空格數(shù)目不固定感局,只需要相同層級(jí)保持一致 |
使用四個(gè)空格作為縮進(jìn)(不推薦使用tab) |
讓我們?cè)賮?lái)看看Yaml的數(shù)據(jù)類(lèi)型:
- 數(shù)組:一組按次序排列的值尼啡,又稱(chēng)為序列(sequence) / 列表(list)
- 對(duì)象:鍵值對(duì)的集合暂衡,又稱(chēng)為映射(mapping)/ 哈希(hashes) / 字典(dictionary)
- 純量(scalars):單個(gè)的、不可再分的值崖瞭。字符串狂巢、布爾值、整數(shù)书聚、浮點(diǎn)數(shù)唧领、Null、時(shí)間雌续、日期
介紹了這么多斩个,讓我們先來(lái)一起學(xué)習(xí)下Yaml的語(yǔ)法...
Yaml語(yǔ)法學(xué)習(xí)
下面我們針對(duì)Yaml的集中類(lèi)型,進(jìn)行逐一學(xué)習(xí)驯杜。需要注意的是萨驶,Yaml的結(jié)構(gòu)標(biāo)識(shí)符前無(wú)需添加空格,但標(biāo)識(shí)符后需要添加一個(gè)空格艇肴,比如:
# 數(shù)組橫杠后添加空格...
- Java
- python
# 對(duì)象冒號(hào)后添加空格...
name: Uranus
數(shù)組
之所以先介紹數(shù)組腔呜,是因?yàn)檫@個(gè)數(shù)據(jù)類(lèi)型最簡(jiǎn)單...
# 推薦
codes:
- Java
- Python
- Ruby
# 也可以
codes: [Java,Python,Ruby]
對(duì)象
# 推薦
name: Uranus
# 也可以
info: {name: Uranus}
純量
我們需要明確純量的定義:單個(gè)的,不可拆分的值再悼,這句話尤為重要核畴。
純量默認(rèn)是無(wú)需添加引號(hào)的,但正如上面說(shuō)的冲九,當(dāng)它可能出現(xiàn)被拆分的情況時(shí)谤草,我們需要將它放在引號(hào)中。
引號(hào)的使用類(lèi)似Linux莺奸,單引號(hào)和雙引號(hào)都可以使用丑孩,雙引號(hào)不會(huì)對(duì)特殊字符轉(zhuǎn)義。
下面集中列舉可能出現(xiàn)的情況:
# 一般字符串灭贷,無(wú)需引號(hào)
name: Uranus
# 數(shù)值
age: 18
# 布爾值
result: true
# 時(shí)間格式
time: 2019-09-03t01:00:05
date: 2019-09-03
# 強(qiáng)制轉(zhuǎn)型時(shí)温学,使用兩個(gè)嘆號(hào)
age: !!str 18
--> { age: '18' }
# 當(dāng)存在空格等特殊字符時(shí),需要添加引號(hào)
name: 'King Uranus'
name1: 'My name is :King Uranus'
# 單引號(hào)轉(zhuǎn)義甚疟,所以出現(xiàn)\\n仗岖,雙引號(hào)不轉(zhuǎn)義
name2: 'My name is :\nKing Uranus'
--> { name: 'My name is \\nKing Uranus'}
name3: "My name is :\nKing Uranus"
--> { name: 'My name is \nKing Uranus'}
# yaml允許換行,但在第二行首位置览妖,需要至少添加一個(gè)空格
name2: 話說(shuō)到一半
喘口氣...
--> { name2: '話說(shuō)到一半 喘口氣...' }
# 表示空值null的幾種方法
var:
var1: null
var2: ~
--> { var: null, var1: null, var2: null }
關(guān)于引用
Yaml支持?jǐn)?shù)據(jù)集之間的引用轧拄,&用來(lái)建立錨點(diǎn)(defaults),<<表示合并到當(dāng)前數(shù)據(jù)讽膏,*用來(lái)引用錨點(diǎn)檩电。
xiaoming: &info
age: 18
sex: male
xiaoli:
<<: *info
--> { xiaoming: { age: 18, sex: 'male' },xiaoli: { age: 18, sex: 'male' } }
Python使用Yaml
寫(xiě)了這么多Yaml的知識(shí),可Python怎么能與Yaml進(jìn)行交互呢?使用Pyyaml俐末。
安裝: pip install pyyaml
導(dǎo)入: import yaml
至于操作料按,簡(jiǎn)直不要太簡(jiǎn)單... yaml只有兩個(gè)方法load、dump鹅搪,而且使用完全和json模塊一樣站绪。但真的如此嗎遭铺?顯然不是...
Yaml安全告警
由于Yaml數(shù)據(jù)存在安全隱患丽柿,在使用pyyaml進(jìn)行l(wèi)oad時(shí),會(huì)給出提示:
YAMLLoadWarning: calling yaml.load() without Loader=... is deprecated, as the default Loader is unsafe. Please
read https://msg.pyyaml.org/load for full details.
所以我們有以下方式解決:
- 添加Loader
info = yaml.load(data,Loader=yaml.SafeLoader)
- 使用語(yǔ)法糖
info = yaml.safe_load(data)
Yaml文件特性
由于Yaml文件可以使用三個(gè)短橫杠 ---
在一個(gè)文件中保存多個(gè)Yaml文檔內(nèi)容魂挂,所以Yaml的方法額外多出了load_all dump_all兩種方法甫题。但這里有個(gè)問(wèn)題,如果使用load_all加載單個(gè)文檔涂召,沒(méi)有問(wèn)題坠非,但如果使用load加載多個(gè)文檔,則會(huì)提示:
yaml.composer.ComposerError: expected a single document in the stream but found another document
所以果正,無(wú)腦的簡(jiǎn)單粗暴炎码,直接使用load_all與dump_all。當(dāng)然秋泳,如果為了寫(xiě)著練習(xí)潦闲,可以判斷文件后,單文件返回dict迫皱,如果多文件將迭代器轉(zhuǎn)化為list后進(jìn)行返回...
示例
未能能讓大家更多的熟悉方法歉闰,我們就寫(xiě)一個(gè)沒(méi)什么用的Yaml單文件與多文件解析器吧。
先拷貝上面的示例卓起,編寫(xiě)兩個(gè)簡(jiǎn)單的yaml文件:
breeze_single.yaml
---
xiaoming: &info
age: 18
sex: male
xiaoli:
<<: *info
breeze.yaml
---
xiaoming: &info
age: 18
sex: male
xiaoli:
<<: *info
---
codes:
- Java
- Python
- Ruby
time: 2019-09-03t01:00:05
date: 2019-09-03
現(xiàn)在讓我們解析打印這兩個(gè)yaml和敬,最終再回寫(xiě)兩個(gè)new_xxx的yaml文件吧。
# -*- coding: utf-8 -*-
# @Author : 王翔
# @WeChat : King_Uranus
# @公眾號(hào) : 清風(fēng)Python
# @Date : 2019/9/3 0:46
# @Software : PyCharm
# @version :Python 3.7.3
# @File : PythonYaml.py
import yaml
from yaml.composer import ComposerError
class YamlLoader:
def __init__(self, file):
self.file = file
def load_choice(self):
with open(self.file, 'r') as f:
data = f.read()
try:
return yaml.safe_load(data)
except ComposerError:
return yaml.safe_load_all(data)
def file_load(self):
info = self.load_choice()
print(info)
if isinstance(info, dict):
self.file_dump(info, single=True)
else:
self.file_dump(info)
def file_dump(self, data, single=None):
with open('new_{}'.format(self.file), 'w', encoding='utf-8') as f:
if single:
f.write(yaml.safe_dump(data))
else:
f.write(yaml.safe_dump_all(data))
yaml_read_single = YamlLoader('breeze_single.yaml')
yaml_read_single.file_load()
yaml_read = YamlLoader('breeze.yaml')
yaml_read.file_load()
output:
>>> {'xiaoming': {'age': 18, 'sex': 'male'}, 'xiaoli': {'age': 18, 'sex': 'male'}}
>>> <generator object load_all at 0x0000000009E76DE0>
# new_breeze.yaml
xiaoli:
age: 18
sex: male
xiaoming:
age: 18
sex: male
---
codes:
- Java
- Python
- Ruby
date: 2019-09-03
result: true
time: 2019-09-03 01:00:05
# new_breeze_single.yaml
xiaoli:
age: 18
sex: male
xiaoming:
age: 18
sex: male
可以看到戏阅,讀寫(xiě)都沒(méi)有問(wèn)題昼弟,但yaml將我們之前的引用,進(jìn)行了重寫(xiě)...但無(wú)傷大雅奕筐。
The End
期待你關(guān)注我的公眾號(hào)清風(fēng)Python
私杜,如果你覺(jué)得不錯(cuò),希望能動(dòng)動(dòng)手指轉(zhuǎn)發(fā)給你身邊的朋友們救欧。
我的github地址:https://github.com/BreezePython