Skip to main content

JSON、YAML、TOML 簡易說明

本文會從什麼是資料序列化開始介紹,並且介紹三種常見的資料格式,以及如何選擇和格式範例,最後是 JSON 讀寫範例。

序列化

序列化 (Serialization) 是將資料結構轉換為可儲存或傳輸的格式,而反序列化則將其還原為程式語言中可操作的資料結構或物件。它是資料交換和配置儲存的核心技術。

  • 序列化:將記憶體中的資料結構或物件轉換為特定格式,使其適合儲存或傳輸
  • 反序列化:將已序列化的資料轉換回程式語言中的資料結構或物件

本文只介紹設定檔常用的 JSON/YAML/TOML 格式。

常見資料格式簡介

  • JSON 是最通用的序列化方式,最大弱點是不支援註解
  • YAML 誕生的目的是設計一個人類可讀的資料格式,解決以往 JSON 不好閱讀、無法註解的問題
  • TOML 最新穎,因為高可讀以及可任意縮排受到歡迎,例如各種 markdown 工具就很喜歡使用 TOML 為配置檔案(例如 Hugo)。
格式特性優點缺點
JSON結構簡單,語法直觀人類可讀性高,跨語言相容性強不支援註解
YAML簡潔,支援註解,可讀性強適合配置檔案格式靈活,易因縮排出錯
TOML結構清晰,易讀易寫專為配置檔案設計相較支援工具較少

格式範例

YAML 誕生的目的是為了人類高可讀性,然而他不規範的縮排讓筆者本身覺得他可讀性比 JSON 還不如,例如 pre-commit 這種格式也是合法的,並且因為沒有括弧所以在複雜設定時就考驗你的眼力,你要往上對齊找到現在在哪個列表或字典中,而不是 JSON 可以用括弧瞬間定位,或者 TOML 每個項目的標題就直接寫清楚了,對我來說 YAML 唯一好用的就是簡單且長的設定,如果包含多種結構會瞬間變得比 JSON 還難讀。除了可讀性問題 The yaml document from hell 還有更多抱怨。

下方範例可以作為 cheatsheet 使用,對照原始資料結構一目了然知道應該如何設定。

# Python 字典結構,包含不同層級的key-value
data = {
"simple_string": "Hello, world", # 第一層 key-value
"simple_integer": 100, # 第一層 key-value
"nested_dict": {
"level_1": {
"level_2": {
"key": "deep_value"
}
},
"first_level_in_nested": "Nested first level"
},
# nested_list 為非同質化數據,"toml" 套件無法讀,要改用 "tomlkit" 套件
"nested_list": [
["a", "b", "c"],
[1, 2, 3, [10, 20, 30]]
],
"mixed_structure": {
"list_in_dict": [
{"id": 1, "name": "Item 1"},
{"id": 2, "name": "Item 2"}
],
"dict_in_list": [
{
"key1": "value1",
"nested": {
"key2": "value2"
}
}
]
},
"boolean_key": True # 第一層 key-value
}

YAML 的解讀方式大概是看到 - 就代表要開始列表了,如果連續每行都有 - 代表這是列表的 0, 1, 2, ... 個元素,如果只有一個 - 隔了幾個才看到下一個 -,就代表這是包含多個字典的列表。

如何選擇

如果要儲存大型數據結構,在這三者選擇毫無疑問就是使用 JSON,其他兩個是給人類讀的。

  • JSON:最通用標準的方式,拿不定主意用他、大型數據用他
  • YAML:需要可讀性的配置檔案
  • TOML:語法簡單,小型配置檔案的首選
  • 高效能:高效能還用文字格式是不是搞錯了什麼?

這樣看似使用 YAML 和 TOML 作為需要手動配置的文件格式是好選擇,然而有一些問題需要注意,首先是 YAML 利用縮排解析資料結構非常反人類,稍微複雜一點的配置解讀難度就指數提高(回想當時在伺服器上用 nano 改 YAML 根本是要了我的命);TOML 的缺點說大不大說小不小,分別有以下幾個:

  1. 字典第一層的一定要寫在 TOML 最上面,無法保持原有位置
  2. 在複雜配置可讀性就大幅降低(至少對我來說)
  3. 異質化的數據不是所有解析工具都支援
  4. 會的人相對少、相關工具也少

TOML 看似很多缺點,但是經歷過 YAML 除錯之後,要我在兩者之間選擇我還是會毫不猶豫選擇 TOML。

YAML 獨有語法

YAML 的 |> 符號用於控制多行字串的格式化,| 會保留換行符,> 會將換行折疊為單一空格。

key: |
Line 1
Line 2
Line 3
key: >
Line 1
Line 2
Line 3

這兩個是一樣的

channels:
- conda-forge
dependencies:
- latexindent.pl

channels:
- conda-forge
dependencies:
- latexindent.pl

同場加映:JSON 讀寫

Python 內置庫 json 有 load/loads/dump/dumps 四種方式

  • 有 s 代表字串處理,沒有 s 代表檔案讀寫
  • load/loads 是反序列化變成物件,dump/dumps 是序列化變成字串
  • 遇到亂碼可以設定 encoding="utf-8" 設定編碼,或者其餘編碼方式
  • 使用 json.dumps(data, indent=4) 可以漂亮印出字典

使用範例如下

import json
data = {"name": "Alice", "age": 25}

# 序列化:來源是一個物件
# 讀取檔案
with open("data.json", "w") as file:
json.dump(data, file)

# 漂亮印出
print(json.dumps(data, indent=4))

# 反序列化:來源是字串
# 載入檔案
with open("data.json", "r") as file:
data = json.load(file)

# 讀取字串形式的字典
json_str = '{"name": "Alice", "age": 25}'
data = json.loads(json_str)

毫不意外的網路上又在亂寫一通,這麼簡單四點一個段落可以水成一篇文章還寫的不清不楚。

同場加映:JSON 第三方套件

內建 json 慢是當然的,這裡列出第三方套件提供選擇:

  1. ujson: 內建 json 的輕量替代品
  2. orjson: 高效的替代品
  3. msgspec: 利用數據類型加速讀取
偷偷罵人

這篇文章原本是想寫一個 YAML cheatsheet,因為 YAML 真的是我遇過最反人類的格式,在 ubuntu server 設定過 docker-compose.yml 就知道用 vim/nano 編輯根本是人間地獄,用縮排解析蠢到不行到底哪個天才想出來的。想一想又覺得可以連 JSON/TOML 一起寫一寫,順便說序列化、反序列化,因為這些內容看網路文章又是一如既往的爛,語言模型十秒寫完的都比這些爛文章還好理解,這些爛文章的存在意義只剩下兩個

  1. 當訓練資料
  2. 浪費大家時間

所以這篇文章我也叫語言模型寫,沒有安全性討論沒有效能比較什麼都沒,很快能讀完,而且就算是笨蛋都看得懂。

prompt

ChatGPT 4o#2025/01/11

第一段先叫他想出段落

我正在寫一篇文章介紹資料相關,從序列化、反序列化,到json/yaml/toml,幫助我完成這兩項任務

1. 想出中文標題/slug,簡短超簡潔易懂,符合google seo
2. 規劃段落

第二段叫他開始寫

根據此規劃寫出「超簡潔」介紹文章,簡潔不代表沒有內容深度,而是去蕪存菁,不講廢話,只講重點,不浪費排版

一切以資訊吸收速度為考量撰寫高可讀、超簡潔文章

不過還是自己改了大概有一半的篇幅。