Following system colour scheme - Python 增強提案 Selected dark colour scheme - Python 增強提案 Selected light colour scheme - Python 增強提案

Python 增強提案 (Python Enhancement Proposals)

PEP 3131 – 支援非 ASCII 識別字

作者:
Martin von Löwis <martin at v.loewis.de>
狀態:
最終 (Final)
類型:
標準軌跡 (Standards Track)
建立日期:
2007 年 5 月 1 日
Python 版本:
3.0
公告歷史:


目錄

摘要

本 PEP 建議在 Python 識別字中支援非 ASCII 字元(例如帶有附加符號的字元、西里爾字母、希臘字母、漢字等)。

原理

全球有許多不熟悉英語,甚至不熟悉拉丁字母系統的人在編寫 Python 程式碼。這些開發者往往希望使用母語來定義類別和函式名稱,而不是被迫為他們想表達的概念翻譯成(通常不準確的)英文。透過使用母語識別字,可以提升該語言使用者對程式碼的清晰度與可維護性。

對於某些語言,存在通用的音譯系統(特別是針對基於拉丁字母的書寫系統)。但對於其他語言,使用者在運用拉丁字母來拼寫母語詞彙時會面臨較大的困難。

常見反對意見

針對這類提議,經常會出現一些反對意見。

人們聲稱,如果必須使用無法從鍵盤輸入的字元才能使用某個函式庫,他們將無法使用它。然而,決定使用函式庫的各種限制應由函式庫的設計者自行決定:使用者可能因為無法取得原始碼(因為未公開)、授權禁止使用,或文件語言無法理解而無法使用該函式庫。希望讓函式庫廣泛被使用的開發者,需要做出多項明確的選擇(例如發佈方式、授權、文件語言以及識別字語言)。這些決定應當永遠由作者來做出,而不是由程式語言的設計者來決定。

特別是那些希望廣泛應用的專案,可能會希望制定一項政策,規定所有識別字、註解和文件都必須使用英語撰寫(請參考 GNU 編碼風格指南作為此類政策的範例)。僅限制識別字使用 ASCII 並不能強制規定註解、文件必須使用英語,或者識別字必須是真實的英語單字,因此無論如何,額外的政策規範仍然是必要的。

語言變更規範

Python 識別字的語法將基於 Unicode 標準附件 UAX-31,並進行如下說明與變更。

在 ASCII 範圍內(U+0001..U+007F),識別字的合法字元與 Python 2.5 相同。本規範僅引入 ASCII 範圍之外的額外字元。對於其他字元,分類方式使用 unicodedata 模組中所包含的 Unicode 字元資料庫版本。

識別字的語法為 <XID_Start> <XID_Continue>*

關於哪些字元具有 XID_Start 或 XID_Continue 屬性的確切規範,可參閱 Python 所使用的 Unicode 資料中的 DerivedCoreProperties 檔案(撰寫此 PEP 時為 4.1 版)。作為參考,這些集合的構建規則列於下方。XID_* 屬性衍生自 ID_Start/ID_Continue,而後者本身又是經由衍生而得。

ID_Start 定義為所有屬於以下一般類別的字元:大寫字母 (Lu)、小寫字母 (Ll)、標題字母 (Lt)、修飾字母 (Lm)、其他字母 (Lo)、字母數位 (Nl)、底線,以及帶有 Other_ID_Start 屬性的字元。XID_Start 接著會在正規化下封閉此集合,移除所有其 NFKC 正規化形式不再屬於 ID_Start ID_Continue* 的字元。

ID_Continue 定義為 ID_Start 中的所有字元,加上非間隔標記 (Mn)、間隔組合標記 (Mc)、十進位數字 (Nd)、連接符號 (Pc),以及帶有 Other_ID_Continue 屬性的字元。同樣地,XID_Continue 在 NFKC 正規化下封閉此集合;它還加入了 U+00B7 以支援加泰隆尼亞語。

所有識別字在解析時都會轉換為正規形式 NFKC;識別字的比較亦基於 NFKC。

列出 Unicode 4.1 所有合法識別字字元的非規範性 HTML 檔案,可參見 https://web.archive.org/web/20081016132748/http://www.dcl.hpi.uni-potsdam.de/home/loewis/table-3131.html

政策規範

作為 Python 編碼風格的補充,規定以下政策:Python 標準函式庫中的所有識別字「必須」僅使用 ASCII 識別字,並在可行情況下「應該」使用英語單字(許多情況下會使用非英語的縮寫與技術術語)。此外,字串常數與註解也必須使用 ASCII。僅有的例外為:(a) 測試非 ASCII 功能的測試案例,以及 (b) 作者姓名。姓名非基於拉丁字母的作者「必須」提供其姓名的拉丁音譯。

作為一個選項,本規範可以應用於 Python 2.x。在該情況下,僅 ASCII 的識別字將繼續作為命名空間字典中的位元組字串物件;包含非 ASCII 字元的識別字將表示為 Unicode 字串。

實作

解析器將需要進行以下變更:

  1. 若在原始碼的 UTF-8 表示中發現非 ASCII 字元,則會進行前向掃描以找到第一個非識別字的 ASCII 字元(例如空格或標點符號)。
  2. 整個 UTF-8 字串會被傳遞給一個函式,將其正規化為 NFKC,並驗證其是否遵循識別字語法。純 ASCII 識別字不會進行此類呼叫,它們將繼續以現有的方式進行解析。Unicode 資料庫必須開始包含 Other_ID_{Start|Continue} 屬性。
  3. 若此規範在 2.x 中實作,必須驗證反射函式庫(如 pydoc)在 Unicode 字串作為 __dict__ 鍵出現時,仍能正常運作。

待決問題

John Nagle 建議考慮 Unicode 技術標準 #39,該標準討論了 Unicode 識別字的安全性機制。目前尚不清楚該標準如何精確地應用於本 PEP;可能的結果包括:

  • 對 xidmodifications.txt 中列為「受限制」的字元發出警告
  • 對使用混合腳本的識別字發出警告
  • 以某種方式執行「混淆偵測」(Confusable Detection)

後兩種方法的演算法具體該如何運作尚不清楚。對於混合腳本,某些混合方式可能應該被允許——這些是否是第 5 節中提到的「通用」(Common) 和「繼承」(Inherited) 腳本?對於混淆偵測,似乎需要兩個識別字來進行比較以判斷是否混淆——是否可以僅對單一識別字應用此機制並發出警告?

在後續討論中,John Nagle 表示他實際上是建議 UTR#36 的「高度受限」(Highly Restrictive) 層級。

幾個人建議允許並忽略格式控制字元(一般類別 Cf),如同 Java、JavaScript 和 C# 的做法。這是否能改善現狀尚不明確(對 RTL 語言可能有幫助);若有需求,未來可以再加入。

有些人希望在執行時期有一個選項來選擇是否支援此 PEP;對於該選項具體為何,以及預設值為何,意見分歧。Guido van Rossum 評論道,傳遞給直譯器的全域旗標是不可接受的,因為它會應用於所有模組。

討論

Ka-Ping Yee 總結了討論與進一步的反對意見如下:

  1. 是否應允許識別字包含任何 Unicode 字母?

    全面允許非 ASCII 識別字的缺點:

    1. Python 將失去可靠地將資訊往返於螢幕或紙張等人類可讀顯示介面的能力。
    2. Python 將變得容易受到新型別的安全漏洞攻擊;提交的程式碼與修補程式將更難以檢查。
    3. 人類將無法再驗證 Python 語法。
    4. Unicode 還很年輕;其問題尚未被充分理解與解決;工具支援仍然薄弱。
    5. 擁有非 ASCII 識別字的語言使用不同的字元集與正規化方案;PEP 3131 的選擇並非顯而易見。
    6. 當數字或運算子靠近時,Unicode 雙向演算法 (bidi) 對 RTL(從右至左)文字會產生極度混亂的顯示順序。
  2. 預設行為應該僅接受 ASCII 識別字,還是應該接受包含非 ASCII 字元的識別字?

    預設僅支援 ASCII 的論點:

    1. 預設支援非 ASCII 識別字會使常見的實務/假設變得細微且無意地錯誤;很少錯誤比顯而易見的錯誤更糟糕。
    2. 在遇到可能非預期的情況時,發出警告比靜默失敗更好。
    3. 當前所有的用法均為純 ASCII;未來的絕大多數用法也將是純 ASCII。
    1. 狹隘的是那些採用 Unicode 的少數群體,而非 ASCII 的倡導者。
    2. 基於與審查 Tab 與空格一致性相同的理由,Python 應審查是否僅使用 ASCII 識別字。
    3. 漸進式的變更更為安全。
    4. 純 ASCII 的預設值有利於開源開發與原始碼分享。
    5. 既有專案無需耗費任何精力去擔心 Unicode 識別字的影響。
  3. 非 ASCII 識別字是否應該是選擇性的?

    各方對於旗標支援的聲音(儘管對於何者應為預設值存在爭論,但似乎沒人表示不應該有一個開關)。

  4. 識別字字元集是否應該是可配置的?

    各方提議並支援可選擇的字元集,以便使用者既能享受使用母語的好處,又能避免混淆/陌生字元的缺點。

  5. 應該允許哪些識別字字元?
    1. 對於 bidi 格式控制字元該怎麼辦?
    2. 其他 ID_Continue 字元呢?看起來像標點符號的字元呢?UTS #39 中的其他建議呢?混合腳本的識別字呢?
  6. 應該使用哪種正規化形式,NFC 還是 NFKC?
  7. 是否應要求原始碼必須以正規化形式存在?

來源:https://github.com/python/peps/blob/main/peps/pep-3131.rst

最後修改:2025-02-11 05:10:05 GMT