後端工坊 2026 年 10 月 10 日

2026-10-10 — Python 3.15 預設編碼改為 UTF-8

primary=https://www.python.org/downloads/release/python-3150/ primary=https://docs.python.org/3.15/whatsnew/3.15.html primary=https://lwn.net/Articles/1099602/

Python 3.15 預設編碼改為 UTF-8

python.org · 2026-10-09

Python 3.15 起,沒有指定 encoding 的 open() 一律使用 UTF-8,不再看系統 locale(PEP 686)。同一版還把 sentinel 與 frozendict 放進 builtins,並新增 lazy import 語法。3.15.0 於 2026-10-09 釋出。

原本的問題

過去 open('flying-circus.txt') 的結果取決於執行環境的 locale。同一份程式在 Linux 開發機、Windows CI、容器內的 C locale 上,可能讀出不同的字元,甚至直接丟出 UnicodeDecodeError。

匯入模組也有類似的老問題:import 在載入時就執行,CLI 工具為了縮短啟動時間,只好把 import 搬進函式內部,程式碼因此變得零碎。

核心改動

UTF-8 預設(PEP 686)。只有在沒給 encoding 參數時才受影響。要退回舊行為,設 PYTHONUTF8=0 或加 -X utf8=0;要明確使用 locale 編碼,用自 3.10 起就有的 encoding='locale'。

# 3.14 以前:依 locale
open('flying-circus.txt')
# 3.15:等同 UTF-8,建議仍寫明
open('flying-circus.txt', encoding='utf-8')

Lazy import(PEP 810)。新的 lazy 軟關鍵字讓模組延後到第一次使用才載入,載入失敗的例外也在第一次使用時才拋出,traceback 會附上原本的 import 陳述式。

lazy import json
lazy from pathlib import Path
print("Starting up...")        # 此時兩者都還沒完整載入
data = json.loads('{"k": 1}')  # json 在這裡才載入
  • lazy 只能寫在模組層級,放進函式、class body 或 try/except/finally 會是 SyntaxError。
  • lazy from module import * 與 lazy from __future__ import ... 也不允許。
  • 可用 -X lazy_imports 或 PYTHON_LAZY_IMPORTS 設為 all 或預設的 normal;舊版相容寫法是在模組內定義 __lazy_modules__ = ["json", "pathlib"]。

frozendict(PEP 814)。不可變的對照表,直接繼承 object,不是 dict 的子類別。鍵值都可雜湊時它就可雜湊,順序被保留但相等比較不看順序。

>>> a = frozendict(x=1, y=2)
>>> hash(a) == hash(frozendict(y=2, x=1))
True

其他。sentinel(PEP 661)提供帶簡潔 repr 的唯一哨兵值,複製後身分不變,可用於 | 型別運算;PEP 798 讓推導式支援 [*L for L in lists] 這類展開;PEP 831 預設以 frame pointer 編譯 CPython,讓 profiler 與 eBPF 工具的堆疊回溯更可靠。實驗性 JIT 在 x86-64 Linux 上相對標準直譯器的幾何平均提升為 7-8%,數字出自發布頁。

影響範圍

  • 在 Windows 或非 UTF-8 locale 讀寫舊文字檔的程式。以前靠 locale 隱式讀 Big5、cp950 等檔案的,升級後會解碼失敗或出現亂碼。先用 what's new 提到的選用 encoding warning 找出沒寫 encoding 的呼叫,再逐一補上。
  • 用 isinstance(arg, dict) 做參數檢查的函式庫。frozendict 不是 dict,會被擋掉。改成 isinstance(arg, (dict, frozendict)),或用 collections.abc.Mapping。
  • 編譯 C、C++、Rust 擴充的建置系統。發布頁說明 frame pointer 旗標會透過 sysconfig 傳遞;不繼承 Python 旗標的原生元件需自行加上等效旗標,否則單一元件缺少 frame pointer 就可能讓整個程序的堆疊回溯失效。
  • macOS 使用者。發布頁警告在 macOS 27.0 上 IDLE 與其他 tkinter GUI 的選單開啟對話框時可能卡住,建議暫緩升級該系統,追蹤 issue #158053。

發布頁未列出任何移除項目;完整清單請看 what's new 文件,本文只讀到其前半部。

原始來源:Python 3.15.0 發布頁、What's New in Python 3.15、LWN 發布報導


End of article
0
Would love your thoughts, please comment.x
()
x