---
# System prepended metadata

title: 【Python 筆記】JSON 格式讀寫
tags: [python, 數據分析, Python, 字串處理, 程式語言]

---

# 【Python 筆記】JSON 格式讀寫

[TOC]

感謝您點進本篇文章，我是 LukeTseng，該系列主要以筆記加上口語白話形式學習 Python，若文章某處有誤敬請告知，非常感謝。

## JSON 是啥？

JSON 全名是 **J**ava**S**cript **O**bject **N**otation，這是一種輕量級的資料交換格式，以純文字方式儲存和傳輸資料。雖然名字有 javascript，但他完全獨立於這個程式語言，幾乎所有現代程式語言都支援 JSON 格式。

JSON 的語法很簡單，與 Python 中的字典相似，同樣是採用鍵值對（key-value）的方式組織資料。

JSON 由兩個主要結構組成：

1. 物件（Object）使用大括號 `{}` 包起來，含鍵值對。
2. 陣列（Array）使用中括號 `[]` 包裹，含有序的值列表。

### JSON 的資料型態

JSON 支援六種資料型態，分為簡單型態和複雜型態：

- 簡單型態：
    - 字串（string）：必須用雙引號包裹，如 `"name": "LukeTseng"`。
    - 數字（Number）：可為整數或浮點數，如 `"age": 25` 或 `"price": 99.9`。
    - 布林值（Boolean）：只能是 `true` 或 `false`，不需要引號。
    - 空值（Null）：表示空值，使用 `null`。
- 複雜類型：
    - 物件（Object）：無序的鍵值對集合，用大括號 `{}` 包起來。
    - 陣列（Array）：有序的值集合，用中括號 `[]` 包起來。

### JSON 的範例

取自：https://json.org/example.html

```
{
    "menu": {
      "id": "file",
      "value": "File",
      "popup": {
        "menuitem": [
          {"value": "New", "onclick": "CreateNewDoc()"},
          {"value": "Open", "onclick": "OpenDoc()"},
          {"value": "Close", "onclick": "CloseDoc()"}
        ]
      }
    }
}
```

## JSON in Python

Python 本身就有內建 JSON 的套件，使用 `import json` 這行程式碼即可使用。

這個套件主要就用到以下這四個函式：

1. `json.dumps()`：將 Python **物件**轉換成 JSON 字串。
2. `json.loads()`：將 JSON **字串**轉換成 Python 物件。
3. `json.dump()`：將 Python **物件**寫入 JSON 檔案。
4. `json.load()`：從 JSON 檔案讀取資料到 Python 物件。

上面四個函式其實是兩個函式，因為你會發現 dump 加一個 s 就是字串的意思。

下表關聯了 JSON 資料型態跟 Python 物件的關係：

| Python | JSON |
| -------- | -------- |
| 字典（Dict） | 物件（Object） | 
| 列表（List） | 陣列（Array） |
| 字串（String） | 字串（String） |
| 數字（Number） | 數字（Number） |
| True/False | true/false |
| None | null |

### 1. json.dumps()

語法：

```python
json.dumps(obj, skipkeys=False, ensure_ascii=True,
allow_nan=True, indent=None, separators=None,
sort_keys=False)
```

- obj：要轉換的 Python 物件（字典、列表、字串等）。
- skipkeys：跳過不可序列化的 key，而非引發錯誤。
- ensure_ascii：如果為 True（預設值），則跳脫（Escape）非 ASCII 字元；設為 False 則保留它們。
- allow_nan：允許特殊浮點數值（NaN、Infinity）。
- indent：縮排，可指定為某個數值。
- separators：更改預設分隔符號。
- sort_keys：按照字典序對字典鍵進行排序

範例（Python 字典轉 JSON）：

```python=
import json

# Python Dict
student = {
    "name": "LukeTseng",
    "age": 18,
    "gpa": 4.3,
    "courses": ["演算法", "資料結構", "作業系統"],
    "level" : "SSR",
}

# 轉換成 JSON 字串
json_string = json.dumps(student)
print(json_string)
```

Output：

```
{"name": "LukeTseng", "age": 18, "gpa": 4.3, "courses": ["\u6f14\u7b97\u6cd5", "\u8cc7\u6599\u7d50\u69cb", "\u4f5c\u696d\u7cfb\u7d71"], "level": "SSR"}
```

看來輸出遇到編碼問題了，那這時候只要把 `ensure_ascii = False` 就好了，因為他預設是開著的，所以會自動把非 ASCII 字元給轉成 Unicode 編碼。

再試一次：

```python=
import json

# Python Dict
student = {
    "name": "LukeTseng",
    "age": 18,
    "gpa": 4.3,
    "courses": ["演算法", "資料結構", "作業系統"],
    "level" : "SSR",
}

# 轉換成 JSON 字串
json_string = json.dumps(student, ensure_ascii=False)
print(json_string)
```

Output：

```
{"name": "LukeTseng", "age": 18, "gpa": 4.3, "courses": ["演算法", "資料結構", "作業系統"], "level": "SSR"}
```

你會看到輸出是一行的，這時候可以用 indent 參數調整縮排，讓結果美化：

```python=
import json

# Python Dict
student = {
    "name": "LukeTseng",
    "age": 18,
    "gpa": 4.3,
    "courses": ["演算法", "資料結構", "作業系統"],
    "level" : "SSR",
}

# 轉換成 JSON 字串
json_string = json.dumps(student, ensure_ascii=False, indent=4)
print(json_string)
```

Output：

```
{
    "name": "LukeTseng",
    "age": 18,
    "gpa": 4.3,
    "courses": [
        "演算法",
        "資料結構",
        "作業系統"
    ],
    "level": "SSR"
}
```

### 2. json.loads()

語法：

```
json.loads(s)
```

- `s`：有效的 JSON 字串（可為 str、bytes 或 bytearray 類型）

範例：

```python=
import json

# 收到的 JSON 字串
json_data = """
{"menu": {
  "id": "file",
  "value": "File",
  "popup": {
    "menuitem": [
      {"value": "New", "onclick": "CreateNewDoc()"},
      {"value": "Open", "onclick": "OpenDoc()"},
      {"value": "Close", "onclick": "CloseDoc()"}
    ]
  }
}}
"""

# 轉成 Python 字典
menu = json.loads(json_data)
print(menu)
print(menu['menu']['id'])  # file
print(type(menu))  # <class 'dict'>
```

Output：

```
{'menu': {'id': 'file', 'value': 'File', 'popup': {'menuitem': [{'value': 'New', 'onclick': 'CreateNewDoc()'}, {'value': 'Open', 'onclick': 'OpenDoc()'}, {'value': 'Close', 'onclick': 'CloseDoc()'}]}}}
file
<class 'dict'>
```

### 3. json.dump()

語法同 `json.dumps()`。

範例：

```python=
import json

# 準備要儲存的資料
students = [
    {"name": "LukeTseng", "score": 100},
    {"name": "陳圈翔", "score": 87},
    {"name": "楊1停", "score": 11}
]

# 寫入檔案
with open('students.json', 'w', encoding='utf-8') as file:
    json.dump(students, file, indent=4, ensure_ascii=False)
```

若目錄沒有檔案的話會自動生成一份檔案，有的話則會覆寫整個檔案。

結果（`students.json`）：

```jsonld=
[
    {
        "name": "LukeTseng",
        "score": 100
    },
    {
        "name": "陳圈翔",
        "score": 87
    },
    {
        "name": "楊1停",
        "score": 11
    }
]
```

### 4. json.load()

語法同 `json.loads()`。

範例：

沿用上一份範例生成的 `students.json`。

```python=
import json

# 讀取檔案
with open('students.json', 'r', encoding='utf-8') as file:
    students = json.load(file)

print(students)

for student in students:
    print(f"{student['name']} 的分數是 {student['score']}")
```

Output：

```
[{'name': 'LukeTseng', 'score': 100}, {'name': '陳圈翔', 'score': 87}, {'name': '楊1停', 'score': 11}]
LukeTseng 的分數是 100
陳圈翔 的分數是 87
楊1停 的分數是 11
```

## 總結

JSON 由兩個主要結構組成：物件（Object）使用大括號 `{}` 包起來，以及陣列（Array）使用中括號 `[]` 包起來。

JSON 支援六種資料型態：

簡單型態：

* 字串（String）：必須用雙引號包裹，如 `"name": "LukeTseng"`
* 數字（Number）：可為整數或浮點數
* 布林值（Boolean）：只能是 `true` 或 `false`
* 空值（Null）：表示空值，使用 `null`

複雜型態：

* 物件（Object）：無序的鍵值對集合。
* 陣列（Array）：有序的值集合。

### Python 的 JSON 套件

Python 內建的 json 套件提供四個主要函式：

* json.dumps()：將 Python 物件轉換成 JSON 字串（s 代表 string）
* json.loads()：將 JSON 字串轉換成 Python 物件
* json.dump()：將 Python 物件寫入 JSON 檔案
* json.load()：從 JSON 檔案讀取資料到 Python 物件

Python 物件對應 JSON 資料型態關係：

| Python | JSON |
| -------- | -------- |
| 字典（Dict） | 物件（Object） | 
| 列表（List） | 陣列（Array） |
| 字串（String） | 字串（String） |
| 數字（Number） | 數字（Number） |
| True/False | true/false |
| None | null |

`json.dumps()` or `json.dump()` 常用參數：

* `ensure_ascii`：預設為 True 會跳脫非 ASCII 字元，設為 False 可保留中文字元
* `indent`：設定縮排數值，美化輸出格式
* `sort_keys`：按字典序排序鍵
* `skipkeys`：跳過不可序列化的鍵

## 參考資料

[json.loads() in Python - GeeksforGeeks](https://www.geeksforgeeks.org/python/json-loads-in-python/)

[json.dumps() in Python - GeeksforGeeks](https://www.geeksforgeeks.org/python/json-dumps-in-python/)

[Python3 JSON 数据解析 | 菜鸟教程](https://www.runoob.com/python3/python3-json.html)

[JSON with Python - GeeksforGeeks](https://www.geeksforgeeks.org/python/json-with-python/)

[JSON 檔案操作 - Python 教學 | STEAM 教育學習網](https://steam.oxxostudio.tw/category/python/library/json.html)

[JSON Example](https://json.org/example.html)