【適合初學者】使用 Python 安全讀取 YAML 檔案的方法|safe_load 使用方式與錯誤對策徹底解析

目次

1. 如何在 Python 中讀取 YAML?|本文概要與目標讀者

想在 Python 中處理 YAML 的您

在 Python 中開發應用程式或工具時,會越來越多情況想要使用 YAML 格式來處理「設定檔」或「外部資料的管理」。特別是 YAML 比 JSON 更具可讀性,且能以簡單的描述方式撰寫,因此在工程師或資料科學家之間,也是一種極受歡迎的資料格式。 例如,以下這些用途就需要讀取 YAML:
  • 將 Web 應用程式或腳本的設定檔外部化
  • 想在 Python 中解析Docker Compose 或 Kubernetes的設定檔
  • 想用 YAML 管理機器學習框架的參數
另一方面,也經常聽到初學者說「不知道該如何讀取 YAML 檔案」「出現錯誤,無法順利讀取」等困擾。

本文可學到的事

這篇文章將以易懂的方式,向初學者說明在 Python 中安全且確實讀取 YAML 檔案的方法。具體來說,將涵蓋以下重點:
  • YAML 檔案的基本結構與特點
  • Python 中的讀取方法(safe_load() 的用法)
  • 常見錯誤及其對策
  • 多重文件讀取或設定檔的實務範例
此外,還會觸及安全性方面的注意事項,以及 load()safe_load() 的差異等,不太為人知的情資。最後,還準備了常見問題(FAQ),您的疑問一定能迎刃而解。

目標讀者

這篇文章的對象為以下人士:
  • 想在 Python 中使用 YAML 的初學者~中級者
  • 需要處理設定檔的開發者
  • 對 PyYAML 的用法感到不安的人
  • 想詳細了解 safe_load() 或錯誤對應的人
如果您希望未來在 Python 開發中提升效率,則掌握 YAML 的處理方式將是重大的一步。 接下來的章節,將逐步說明 YAML 的概要及在 Python 中的處理方式。首先,從「YAML 是什麼?」開始吧。

2. YAML 是什麼?|與 JSON 的差異與特點簡單比較

YAML 是什麼?

YAML(讀作 yamu-er,或 yamuru)是「YAML Ain’t Markup Language(YAML 不是標記語言)」的遞迴縮寫,主要為了讓人類更容易讀寫結構化資料而設計的格式。與 Python 或 Ruby 等程式語言相性良好,常被用於設定檔或資料交換的場合。 YAML 使用縮排來表現階層結構,簡單且直觀的描述是其主要特點。

與 JSON 的差異

YAML 與 JSON 用於類似的用途,但兩者有幾個明確的差異。以下比較代表性的項目。
比較項目YAMLJSON
可讀性高(對人類友好)中等(對機器友好)
註解的記述可能(使用 #不可
檔案大小傾向較小(符號較少)稍大
資料結構的表現自由度更高(複雜結構也 OK)以陣列・物件為中心
擴展性高(可定義自有結構)有限制
支援情況部分有限制廣泛支援

YAML 的優點

使用 YAML 有以下優點:
  • 直觀的寫法:類似 Python 的縮排,容易掌握結構
  • 可寫註解:方便在設定檔中添加補充說明
  • 不冗長:不需要 JSON 般的中括弧或雙引號
  • 對人類友好:非工程師也能輕鬆閱讀與修改

YAML 的使用場合

YAML 常被以下工具或系統使用:
  • Docker Composedocker-compose.yml
  • Kubernetes 的設定檔(Pod 或 Service 的定義)
  • CI/CD 工具(GitHub Actions、GitLab CI 等)
  • 機器學習函式庫(PyTorch Lightning 或 Hydra 等)
  • Web 應用程式或腳本的設定檔
也就是說,學會處理 YAML 將在現代開發現場中成為強大的武器。
侍エンジニア塾

3. 使用 Python 處理 YAML 的準備|PyYAML 的安裝

什麼是 PyYAML?

使用 Python 讀取或寫入 YAML 檔案時,通常會使用外部程式庫「PyYAML」。PyYAML 是一個基於 YAML 1.1 規格的簡單且功能豐富的程式庫,因為它不包含在 Python 的標準程式庫中,因此需要另外安裝。 使用 PyYAML 後,可以將 YAML 檔案作為 Python 的字典(dict)或清單(list)來處理。這樣一來,設定檔案的讀寫以及結構化資料的操作就能更直觀地進行。

PyYAML 的安裝方法

PyYAML 的安裝非常簡單。如下所示,可以使用 pip 在命令列(或終端機)中安裝。
pip install pyyaml
※如果環境中沒有 pip,則使用 python -m pip install pyyaml 也沒問題。

建議使用虛擬環境

如果想分離開發環境,建議在 虛擬環境(venv 或 conda) 中安裝。處理多個專案時,程式庫的版本管理會更容易。
# 虛擬環境的建立
python -m venv venv

# 啟用虛擬環境
# Windows 的情況
venv\Scripts\activate
# macOS/Linux 的情況
source venv/bin/activate

# 安裝 PyYAML
pip install pyyaml

安裝確認方法

安裝後,可以在 Python 的互動模式(REPL)或腳本中如以下所述,來確認程式庫是否能正確匯入。
import yaml
print(yaml.__version__)
如果沒有出現錯誤,則 PyYAML 已正常安裝。確認版本有助於未來的故障排除。

4. 【基本】使用 Python 讀取 YAML 檔案的方法(safe_load 的用法)

最基本的讀取方法:safe_load()

使用 PyYAML 讀取 YAML 檔案時,最常使用的函數是 safe_load()。這個函數是為了安全讀取 YAML 而設計的函數,可以將讀取的資料取得為 Python 的字典(dict)或列表(list)。 首先,讓我們看看基本的 YAML 檔案及其讀取程式碼。

範例 YAML 檔案(config.yaml

app:
  name: SampleApp
  version: 1.0.0
debug: true
servers:
  - host: localhost
    port: 8000
  - host: example.com
    port: 443
像這樣,包含巢狀結構或列表的 YAML 檔案,是非常適合用作設定檔案的形式。

Python 中的讀取程式碼範例

使用以下程式碼,可以讀取上述的 YAML 檔案:
import yaml

with open('config.yaml', 'r', encoding='utf-8') as f:
    config = yaml.safe_load(f)

print(config)

輸出範例(Python 的字典形式)

{
  'app': {'name': 'SampleApp', 'version': '1.0.0'},
  'debug': True,
  'servers': [
    {'host': 'localhost', 'port': 8000},
    {'host': 'example.com', 'port': 443}
  ]
}
像這樣,YAML 檔案可以直接作為 Python 的原生資料結構來處理,因此可以順利用於後續的處理。

open()函數中指定編碼很重要

特別是處理包含日文的 YAML 檔案時,請不要忘記在 open()函數中encoding='utf-8' 指定。如果省略,在 Windows 環境中可能會發生文字亂碼。

小提示:with語法的活用

在讀取檔案時,像 with open(...) as f: 這樣使用with語法,可以防止檔案關閉遺漏,並安全地進行處理。這是 Python 的最佳實踐,推薦的寫法。
年収訴求

5. safe_load 和 load 的差異|Python 中 YAML 讀取的注意事項

safe_load()load() 有什麼不同?

PyYAML 有多個用來讀取 YAML 檔案的函數,但最容易混淆的便是 safe_load()load() 的差異。 乍看之下,兩者都是用來將 YAML 讀取為 Python 資料的函數,但在安全性與功能方面有很大的差異。若使用錯誤,可能會有被外部惡意 YAML 檔案執行程式碼的危險,因此理解並正確區分使用非常重要。

safe_load() 的特點(安全的讀取)

import yaml

with open('config.yaml', 'r', encoding='utf-8') as f:
    data = yaml.safe_load(f)
  • 應使用的基本函數
  • 安全性高(不讀取任意的 Python 物件)
  • 限制於基本資料型(字典、列表、字串、數值等)
  • 嘗試讀取未知的型別或物件時會發生錯誤
safe_load() 如其名所示,是用來進行「安全的讀取」的函數,在處理設定檔案或外部資料時,大多數情況下使用此函數是最佳選擇。

load() 的特點(靈活但有風險)

import yaml

with open('config.yaml', 'r', encoding='utf-8') as f:
    data = yaml.load(f, Loader=yaml.FullLoader)
  • 能更靈活地解釋 YAML
  • 可還原 Python 物件(例如:函數、類別實例等)
  • 由於安全性風險,必須指定 Loader
事實上,在舊版的 PyYAML 中,可以單獨使用 load(),但現在要求明確指定 Loader。若不指定任何東西使用,會發生以下類似的警告或錯誤:
yaml.YAMLLoadWarning: calling yaml.load() without Loader=... is deprecated
這是因為 load() 在過去包含了可能執行任意 Python 物件的漏洞。也就是說,若讀取不正當的 YAML 檔案,可能會無意中執行 Python 程式碼的風險。

Loader 的種類(安全性和靈活性的差異)

Loader 名稱特點推薦度
SafeLoader僅讀取基本型別(安全)
FullLoader允許更多 Python 型別(注意安全性)
UnsafeLoader允許讀取任意物件(危險)×

結論:通常使用 safe_load()

如果您只是將 YAML 檔案作為設定檔案或外部資料讀取,那麼 safe_load() 就足夠了,而且應該使用它。load() 僅限於特殊用途(例如,想要反序列化自製的 Python 物件等情況)使用。

6. 常見錯誤及其解決方法|Python YAML 讀取的陷阱

YAML 讀取時絆倒的原因是什麼?

YAML 是一種非常簡單且易讀的格式,但因此對細微的語法規則非常嚴格。特別是在使用 Python 讀取時,新手容易忽略的一些要點。 在本節中,我們將具體介紹使用 Python 讀取 YAML 檔案時常見的錯誤、其原因以及解決方法。

1. 縮排錯誤導致的語法錯誤

在 YAML 中,縮排是顯示結構的重要元素。如果空格或 Tab 不一致,讀取時就會發生錯誤。

範例:有縮排錯誤的 YAML

user:
  name: Alice
    age: 30

錯誤訊息範例:

yaml.scanner.ScannerError: mapping values are not allowed here

解決方法:

  • 2~4 個空格統一縮排(不要使用 Tab)
  • 子元素要比父元素縮排更深

2. 檔案編碼導致字元亂碼

如果 YAML 檔案包含日文等非 ASCII 字元,若不適當指定編碼,就會發生字元亂碼或解碼錯誤。

錯誤範例:

UnicodeDecodeError: 'cp932' codec can't decode byte...

解決方法:

with open('config.yaml', 'r', encoding='utf-8') as f:
    data = yaml.safe_load(f)
  • 明確指定 encoding='utf-8' 即可解決
  • 在 Windows 環境中特別容易忘記的要點

3. 檔案路徑錯誤/不存在的檔案

雖然是簡單的錯誤,但如果指定的 YAML 檔案不存在,就會發生 FileNotFoundError

錯誤範例:

FileNotFoundError: [Errno 2] No such file or directory: 'config.yaml'

解決方法:

  • 確認是否以絕對路徑或正確的相對路徑指定
  • 檢查檔案名稱或副檔名是否有輸入錯誤
  • 確認檔案是否位於與腳本相同的目錄

4. 使用 safe_load 讀取的結果為None

即使 YAML 的語法本身正確,如果檔案內容為空或僅有註解,也會發生這種現象。

範例:

# 這個檔案中沒有任何設定

結果:

data = yaml.safe_load(f)
print(data)  # 輸出: None

解決方法:

  • 確認檔案中是否有記述有效的 YAML 資料
  • 僅有註解或空白時,返回 None 是正常的行為

5. 過於複雜的 YAML 結構解析錯誤

在大規模且巢狀深的 YAML 檔案中,由於語法錯誤或錯誤使用錨點/別名,也可能發生錯誤。

解決方法:

  • 逐步確認語法(以小區段為單位驗證)
  • 建議捕捉 yaml.YAMLError 例外並確認詳細訊息
try:
    with open('config.yaml', 'r', encoding='utf-8') as f:
        data = yaml.safe_load(f)
except yaml.YAMLError as e:
    print(f"YAML 讀取錯誤: {e}")

總結:發生錯誤時不要慌張,檢查語法和環境

只要在撰寫時稍加注意,YAML 就是非常易於處理的格式。如果發生錯誤,請檢查以下要點:
  • 縮排是否正確(是否未使用 Tab)
  • 檔案的編碼是否為 UTF-8
  • 檔案是否存在
  • YAML 的內容是否正確記述

7. 應用:讀取多個文件的 YAML 文件的方法(safe_load_all)

YAML 可以包含多個文件在單一文件中

YAML 的一個主要特點是,可以在一個文件中定義多個資料區塊(文件),這樣可以分割設定或配置,同時用一個檔案來統一管理。 文件之間使用 ---(三個連字符)來明確分隔。

多個文件的 YAML 檔案範例(multi.yaml)

# 伺服器設定1
---
server:
  host: localhost
  port: 8080

# 伺服器設定2
---
server:
  host: example.com
  port: 443
這樣寫的 YAML 檔案擁有兩個獨立的資料區塊,需要個別讀取每個區塊。

yaml.safe_load_all() 的使用方法

在 PyYAML 中,為了讀取多個文件,準備了 safe_load_all() 函數。這是將檔案內的所有 YAML 文件作為迭代器(可迭代物件)返回的函數。
import yaml

with open('multi.yaml', 'r', encoding='utf-8') as f:
    documents = yaml.safe_load_all(f)
    for doc in documents:
        print(doc)

執行結果(輸出範例):

{'server': {'host': 'localhost', 'port': 8080}}
{'server': {'host': 'example.com', 'port': 443}}
這樣,每個文件可以作為字典逐一取得,透過迴圈處理來靈活運用。

注意 safe_load() 的差異

一般的 safe_load() 只讀取第一個文件,因此不適合對應多個文件的檔案。
函數名對應的 YAML 格式回傳值的形式
safe_load()僅單一文件資料(字典或列表等)
safe_load_all()對應多個文件迭代器(迴圈處理)

也可以將讀取的文件轉換為列表

有時,可能想要將所有文件作為列表統一取得。在這種情況下,使用以下的 list() 即可。
with open('multi.yaml', 'r', encoding='utf-8') as f:
    documents = list(yaml.safe_load_all(f))
這樣,可以以列表形式批次處理,或使用索引指定來存取。

注意事項:並非所有 YAML 檔案都對應多個文件

對沒有用 --- 分隔的 YAML 檔案使用 safe_load_all() 也沒有問題,但結果只會是單一文件。也就是說,safe_load_all() 是萬能的,但如果不是多個文件,就會和 safe_load() 有相同的行為,請記住這一點。

8. 【補足】使用 YAML 作為設定檔案時的要點

為什麼 YAML 適合用作設定檔案?

YAML 具備 人類易於讀寫的語法 以及 巢狀結構的靈活表現力,因此在許多專案中被採用為「設定檔案」。特別是在使用 Python 開發的應用程式或工具中,使用 YAML 可以讓 設定更容易理解,並提升維護性。 在以下用途中,YAML 非常有用:
  • Web 應用程式的環境設定(生產/開發/測試)
  • 機器學習的超參數設定
  • 腳本的行為切換
  • API 金鑰等外部依賴資訊的管理(※機密資訊的管理需注意)

實用的 YAML 設定檔案範例

app:
  name: MyApp
  mode: production

logging:
  level: INFO
  file: logs/app.log

database:
  host: localhost
  port: 5432
  user: admin
  password: secret
如此一來,將構成元素依據區段彙整,任何人一看就能了解結構的設定檔案。與 JSON 不同,能自由撰寫註解的這一點在實務上也非常重要。

活用巢狀結構的設定階層化

YAML 使用縮排來表現階層,因此也能直覺地表現複雜的設定。例如,想依環境區分設定時,也能如以下方式彙整:
env:
  dev:
    db: dev-db.local
    debug: true
  prod:
    db: prod-db.server
    debug: false
在 Python 端讀取此設定,即可透過環境變數等自動選擇適當的設定。

能以註解明示意圖

YAML 中可以使用 # 來撰寫註解。藉此,能將「為什麼是這樣的設定」「何時該變更」等資訊 直接記述在設定檔案內,這是很大的優點。
# 應用程式的模式設定(dev, test, production 其中之一)
mode: production
JSON 中無法撰寫註解,因此有無法提供此類補充的限制。

執行時讀取 YAML 的程式碼範例(應用)

以下是在 Python 腳本端讀取 YAML 設定並應用到應用程式的範例:
import yaml

with open('settings.yaml', 'r', encoding='utf-8') as f:
    config = yaml.safe_load(f)

app_name = config['app']['name']
mode = config['app']['mode']
db_host = config['database']['host']
如此一來,將 YAML 檔案視為 Python 的字典來處理,即可 不需在程式碼中硬編碼設定值 來進行管理。

注意事項:機密資訊的處理需十分注意

YAML 雖然對人類來說易於處理,但同時也是 以明文儲存的形式。因此,在 YAML 檔案中記述 API 金鑰或密碼等機密資訊時,需要以下措施:
  • 使用 .gitignore 防止提交到儲存庫
  • .env 檔案等結合,從 YAML 只進行參照
  • 套用加密或存取限制

9. 常見問題(FAQ)

在本節中,我們將以問答形式說明在 Python 中讀取 YAML 檔案時常見的疑問,以及初學者容易卡住的要點。這些內容在實際專案中使用時也很有幫助,請務必查看。

Q1. YAML 和 JSON,在 Python 中哪個比較好處理?

A. YAML 可讀性高,作為設定檔案使用非常方便。 Python 中 JSON 也由標準函式庫支援,但 YAML 因為可以寫註解結構看起來清楚等原因,在設定檔案用途上,YAML 比較好處理的感覺的人很多。不過,在重視處理速度或資料交換相容性的場合,JSON 也常被偏好。

Q2. yaml.load() 不能使用嗎?

A. 原則上使用 safe_load() 比較安全。 load() 雖然彈性高,但可以還原任意的 Python 物件,因此有安全性風險。 如果讀取惡意的 YAML 檔案,可能會執行意想不到的程式碼,因此基本上推薦使用 safe_load()。 如果有必要使用 load() 的話,請像 Loader=yaml.FullLoader 這樣明確指定,並以注重安全性的方式實作。

Q3. 讀取的 YAML 內容變成空的(None)是為什麼?

A. 這是 YAML 檔案為空或只有註解時的正常動作。
# 這個檔案還沒有設定
讀取上述這樣的檔案時,safe_load() 的傳回值會變成 None。這不是異常,而是 YAML 有效的「空資料」。請確認檔案內容是否正確描述。

Q4. YAML 檔案中可以像變數一樣重複使用值嗎?

A. YAML 有「錨點」和「別名」這樣的機制。
default: &defaults
  timeout: 30
  retries: 3

service1:
  <<: *defaults
  host: service1.local

service2:
  <<: *defaults
  host: service2.local
像這樣,使用 & 來記述錨點(定義)、* 來記述別名(參照),就可以在多處重複使用相同的設定。不過,在 PyYAML 中使用這個語法時,可能需要特定版本或 Loader 設定,因此請事先確認動作。

Q5. 在 Windows 環境中日文會出現亂碼。該怎麼辦?

A. 在讀取檔案時明確指定編碼即可解決。
with open('config.yaml', 'r', encoding='utf-8') as f:
    data = yaml.safe_load(f)
Windows 的預設文字碼(cp932)無法正確讀取以 UTF-8 寫成的 YAML 檔案。務必明確指定 encoding='utf-8'

Q6. 如果 YAML 檔案分成多個設定區塊要怎麼讀取?

A. 使用 safe_load_all() 就可以讀取多個文件。
---
app: App1
port: 3000
---
app: App2
port: 4000
像這樣的檔案,可以用 yaml.safe_load_all() 逐一處理:
with open('multi.yaml', 'r', encoding='utf-8') as f:
    for doc in yaml.safe_load_all(f):
        print(doc)

10. 總結|掌握Python中的YAML讀取

回顧YAML讀取從基礎到應用的內容

本文針對「想用Python讀取YAML檔案」的人,從基本用法開始,到常見錯誤的處理方法、多重文件以及作為設定檔案的應用範例,一步步詳細說明。 再次總結本文的重點:
  • PyYAML的安裝:要在Python中處理YAML,首先需要 pip install pyyaml
  • 基本的讀取yaml.safe_load() 就能安全且簡單地將YAML讀取為字典或清單。
  • 錯誤對策:縮排或編碼錯誤是常見的問題。語法檢查和encoding='utf-8'很重要。
  • load()的差異:如果重視安全性,應該使用 safe_load()load()必須指定適當的Loader。
  • 多重文件對應:使用safe_load_all(),就能靈活處理單一檔案內的多個設定區塊。
  • 作為設定檔案的實用性:可讀性與彈性優異的YAML,是Python專案中的設定管理最佳選擇。

今後步驟:更多活用YAML

現在已經掌握YAML的讀取方法,下一步可以透過以下步驟,在實務中進一步活用:
  • 寫入YAML檔案:使用yaml.dump() 來自動產生設定檔案
  • 與JSON的相互轉換:在與Web API或外部服務聯動時很方便
  • .env檔案或環境變數併用:建構高安全性的設定管理手法
  • 設定的自動載入化:在應用程式啟動時,動態讀取依環境而定的設定檔案
掌握這些,就能讓使用Python的開發變得更彈性且可重複利用。 今後也會繼續以易懂的方式介紹在現場有用的Python技巧與工具的使用方法。請務必加入書籤,反覆活用。 至此,關於Python讀取YAML檔案的說明就完成了。 請習得這些在實務中也能使用的知識,並在您的專案中試著導入YAML。