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

Python 增強提案

PEP 624 – 移除 Py_UNICODE 編碼器 API

作者:
稻田直樹 <songofacandy at gmail.com>
狀態:
最終版
型別:
標準跟蹤
建立日期:
2020年7月6日
Python 版本:
3.11
釋出歷史:
2020年7月8日

目錄

摘要

本 PEP 提議在 Python 3.11 中移除已棄用的 Py_UNICODE 編碼器 API

  • PyUnicode_Encode()
  • PyUnicode_EncodeASCII()
  • PyUnicode_EncodeLatin1()
  • PyUnicode_EncodeUTF7()
  • PyUnicode_EncodeUTF8()
  • PyUnicode_EncodeUTF16()
  • PyUnicode_EncodeUTF32()
  • PyUnicode_EncodeUnicodeEscape()
  • PyUnicode_EncodeRawUnicodeEscape()
  • PyUnicode_EncodeCharmap()
  • PyUnicode_TranslateCharmap()
  • PyUnicode_EncodeDecimal()
  • PyUnicode_TransformDecimalToASCII()

注意

PEP 623 提議移除與 Py_UNICODE 相關的 Unicode 物件 API。另一方面,本 PEP 與 Unicode 物件無關。這些 PEP 之所以分開,是因為它們有不同的動機,需要不同的討論。

動機

總的來說,減少長期棄用且使用者較少的 API 數量是個好主意,因為它不僅提高了 CPython 的可維護性,還有助於 API 使用者和其他 Python 實現。

基本原理

自 Python 3.3 起已棄用

Py_UNICODE 及使用它的 API 自 Python 3.3 起已棄用。

效率低下

所有這些 API 都使用 PyUnicode_FromWideChar 實現。因此,當用戶想要編碼 Unicode 物件時,這些 API 效率低下。

使用不廣泛

在搜尋排名前 4000 的 PyPI 包 [1] 時,只有 pyodbc 使用這些 API。

  • PyUnicode_EncodeUTF8()
  • PyUnicode_EncodeUTF16()

pyodbc 使用這些 API 將 Unicode 物件編碼為位元組物件。因此很容易修復。[2]

替代 API

存在接受 PyObject *unicode 而非 Py_UNICODE * 的替代 API。使用者可以遷移到它們。

已棄用 API 替代 API
PyUnicode_Encode() PyUnicode_AsEncodedString()
PyUnicode_EncodeASCII() PyUnicode_AsASCIIString() (1)
PyUnicode_EncodeLatin1() PyUnicode_AsLatin1String() (1)
PyUnicode_EncodeUTF7() (2)
PyUnicode_EncodeUTF8() PyUnicode_AsUTF8String() (1)
PyUnicode_EncodeUTF16() PyUnicode_AsUTF16String() (3)
PyUnicode_EncodeUTF32() PyUnicode_AsUTF32String() (3)
PyUnicode_EncodeUnicodeEscape() PyUnicode_AsUnicodeEscapeString()
PyUnicode_EncodeRawUnicodeEscape() PyUnicode_AsRawUnicodeEscapeString()
PyUnicode_EncodeCharmap() PyUnicode_AsCharmapString() (1)
PyUnicode_TranslateCharmap() PyUnicode_Translate()
PyUnicode_EncodeDecimal() (4)
PyUnicode_TransformDecimalToASCII() (4)

備註

  1. 缺少 const char *errors 引數。
  2. 沒有公共替代 API。但使用者可以使用通用的 PyUnicode_AsEncodedString() 代替。
  3. 缺少 const char *errors, int byteorder 引數。
  4. 沒有直接替代。但可以使用 Py_UNICODE_TODECIMAL 代替。CPython 使用 _PyUnicode_TransformDecimalAndSpaceToASCII 進行 Unicode 到數字的轉換。

計劃

在 Python 3.11 中移除這些 API。它們已棄用。

  • PyUnicode_Encode()
  • PyUnicode_EncodeASCII()
  • PyUnicode_EncodeLatin1()
  • PyUnicode_EncodeUTF7()
  • PyUnicode_EncodeUTF8()
  • PyUnicode_EncodeUTF16()
  • PyUnicode_EncodeUTF32()
  • PyUnicode_EncodeUnicodeEscape()
  • PyUnicode_EncodeRawUnicodeEscape()
  • PyUnicode_EncodeCharmap()
  • PyUnicode_TranslateCharmap()
  • PyUnicode_EncodeDecimal()
  • PyUnicode_TransformDecimalToASCII()

替代方案

Py_UNICODE* 替換為 PyObject*

如“替代 API”部分所述,某些 API 沒有接受 PyObject *unicode 輸入的公共替代 API。並且某些公共替代 API 存在限制,例如缺少 errorsbyteorder 引數。

我們可以重用已棄用 API 的名稱作為替代公共 API,而不是移除它們。

由於我們已有私有替代 API,因此只是將私有名稱重新命名為公共名稱和已棄用名稱。

重新命名為 重新命名自
PyUnicode_EncodeASCII() _PyUnicode_AsASCIIString()
PyUnicode_EncodeLatin1() _PyUnicode_AsLatin1String()
PyUnicode_EncodeUTF7() _PyUnicode_EncodeUTF7()
PyUnicode_EncodeUTF8() _PyUnicode_AsUTF8String()
PyUnicode_EncodeUTF16() _PyUnicode_EncodeUTF16()
PyUnicode_EncodeUTF32() _PyUnicode_EncodeUTF32()

優點

  • 我們擁有更一致的 API 集。

缺點

  • 向後不相容。
  • 我們需要為不常用的情況維護更多公共 API。
  • 現有的公共 API 足以滿足大多數用例,PyUnicode_AsEncodedString() 可用於其他情況。

Py_UNICODE* 替換為 Py_UCS4*

我們可以將 Py_UNICODE 替換為 Py_UCS4 並取消棄用這些 API。

UTF-8、UTF-16、UTF-32 編碼器內部支援 Py_UCS4。因此 PyUnicode_EncodeUTF8()PyUnicode_EncodeUTF16()PyUnicode_EncodeUTF32() 可以避免建立臨時 Unicode 物件。

優點

  • 當使用 UTF-8、UTF-16、UTF-32 編解碼器將 Py_UCS4* 編碼為位元組物件時,我們可以避免建立臨時 Unicode 物件。

缺點

  • 向後不相容。
  • 我們需要為不常用的情況維護更多公共 API。
  • 其他希望支援 Python/C API 的 Python 實現也需要支援這些 API。
  • 如果我們將來將 Unicode 內部表示更改為 UTF-8,我們只需要為這些 API 保留 UCS-4 支援。

Py_UNICODE* 替換為 wchar_t*

我們可以將 Py_UNICODE 替換為 wchar_t。由於 Py_UNICODE 已經是 wchar_t 的 typedef,所以這是現狀。

sizeof(wchar_t) == 4 的平臺上,當使用 UTF-8、UTF-16 和 UTF-32 編解碼器將 wchar_t* 編碼為位元組物件時,我們可以避免建立臨時 Unicode 物件,就像“將 Py_UNICODE* 替換為 Py_UCS4*”的思路一樣。

優點

  • 向後相容。
  • sizeof(wchar_t) == 4 的平臺上,當使用 UTF-8、UTF-16、UTF-32 編解碼器將 Py_UCS4* 編碼為位元組物件時,我們可以避免建立臨時 Unicode 物件。

缺點

  • 儘管 Windows 是大量使用 wchar_t 的主要平臺,但這些 API 總是需要建立臨時 Unicode 物件,因為 Windows 上 sizeof(wchar_t) == 2
  • 我們需要為不常用的情況維護更多公共 API。
  • 其他希望支援 Python/C API 的 Python 實現也需要支援這些 API。
  • 如果我們將來將 Unicode 內部表示更改為 UTF-8,我們只需要為這些 API 保留 UCS-4 支援。

被拒絕的想法

發出執行時警告

除了現有的編譯器警告,建議發出執行時 DeprecationWarning

但這些 API 目前不釋放 GIL。從這樣的 API 發出警告是不安全的。請看這個例子。

PyObject *u = PyList_GET_ITEM(list, i);  // u is borrowed reference.
PyObject *b = PyUnicode_EncodeUTF8(PyUnicode_AS_UNICODE(u),
        PyUnicode_GET_SIZE(u), NULL);
// Assumes u is still living reference.
PyObject *t = PyTuple_Pack(2, u, b);
Py_DECREF(b);
return t;

如果我們從 PyUnicode_EncodeUTF8() 發出 Python 警告,警告過濾器和其他執行緒可能會改變 list,並且在 PyUnicode_EncodeUTF8() 返回後,u 可能成為懸空引用。

討論

反對意見

  • 移除這些 API 會失去無需臨時 Unicode 即可使用編解碼器的能力。
    • 自 Python 3.3 起,編解碼器無法直接編碼 Unicode 緩衝區而無需臨時 Unicode 物件。所有這些 API 目前都會建立臨時 Unicode 物件。因此,移除它們不會降低任何能力。
  • 為什麼不也移除解碼器 API?
    • 它們是穩定 ABI 的一部分。
    • PyUnicode_DecodeASCII()PyUnicode_DecodeUTF8() 被廣泛使用。棄用它們不值得。
    • 解碼器 API 可以直接從位元組緩衝區解碼,而無需建立臨時位元組物件。另一方面,編碼器 API 無法避免臨時 Unicode 物件。

參考資料


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

最後修改: 2025-02-01 08:55:40 GMT