PEP 624 – Entfernung von Py_UNICODE-Encoder-APIs
- Autor:
- Inada Naoki <songofacandy at gmail.com>
- Status:
- Final
- Typ:
- Standards Track
- Erstellt:
- 06-Jul-2020
- Python-Version:
- 3.11
- Post-History:
- 08-Jul-2020
Zusammenfassung
Dieser PEP schlägt die Entfernung veralteter Py_UNICODE-Encoder-APIs in Python 3.11 vor.
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()
Hinweis
PEP 623 schlägt die Entfernung von Unicode-Objekt-APIs im Zusammenhang mit Py_UNICODE vor. Dieser PEP hingegen bezieht sich nicht auf Unicode-Objekte. Diese PEPs sind getrennt, da sie unterschiedliche Motivationen haben und unterschiedliche Diskussionen erfordern.
Motivation
Generell ist die Reduzierung der Anzahl von APIs, die seit langem veraltet sind und wenige Benutzer haben, eine gute Idee. Dies verbessert nicht nur die Wartbarkeit von CPython, sondern hilft auch API-Benutzern und anderen Python-Implementierungen.
Begründung
Seit Python 3.3 veraltet
Py_UNICODE und APIs, die es verwenden, sind seit Python 3.3 veraltet.
Ineffizient
Alle diese APIs werden mit PyUnicode_FromWideChar implementiert. Daher sind diese APIs ineffizient, wenn der Benutzer ein Unicode-Objekt kodieren möchte.
Nicht weit verbreitet
Bei der Suche in den Top 4000 PyPI-Paketen [1] verwendet nur pyodbc diese APIs.
PyUnicode_EncodeUTF8()PyUnicode_EncodeUTF16()
pyodbc verwendet diese APIs, um Unicode-Objekte in Byte-Objekte zu kodieren. Daher ist es leicht zu beheben. [2]
Alternative APIs
Es gibt alternative APIs, die PyObject *unicode anstelle von Py_UNICODE * akzeptieren. Benutzer können zu ihnen migrieren.
| Veraltete API | Alternative APIs |
|---|---|
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) |
Anmerkungen
- Der Parameter
const char *errorsfehlt. - Es gibt keine öffentliche alternative API. Aber Benutzer können stattdessen die generische
PyUnicode_AsEncodedString()verwenden. - Die Parameter
const char *errors, int byteorderfehlen. - Es gibt keinen direkten Ersatz. Aber
Py_UNICODE_TODECIMALkann stattdessen verwendet werden. CPython verwendet_PyUnicode_TransformDecimalAndSpaceToASCIIzur Konvertierung von Unicode in Zahlen.
Plan
Entferne diese APIs in Python 3.11. Sie sind bereits veraltet.
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()
Alternative Ideen
Ersetze Py_UNICODE* durch PyObject*
Wie im Abschnitt "Alternative APIs" beschrieben, gibt es für einige APIs keine öffentlichen Alternativen, die PyObject *unicode als Eingabe akzeptieren. Und einige öffentliche alternative APIs haben Einschränkungen wie fehlende Parameter errors und byteorder.
Anstatt veraltete APIs zu entfernen, können wir ihre Namen für alternative öffentliche APIs wiederverwenden.
Da wir bereits private alternative APIs haben, handelt es sich lediglich um eine Umbenennung von privaten zu öffentlichen und veralteten Namen.
| Umbenennen zu | Umbenennen von |
|---|---|
PyUnicode_EncodeASCII() |
_PyUnicode_AsASCIIString() |
PyUnicode_EncodeLatin1() |
_PyUnicode_AsLatin1String() |
PyUnicode_EncodeUTF7() |
_PyUnicode_EncodeUTF7() |
PyUnicode_EncodeUTF8() |
_PyUnicode_AsUTF8String() |
PyUnicode_EncodeUTF16() |
_PyUnicode_EncodeUTF16() |
PyUnicode_EncodeUTF32() |
_PyUnicode_EncodeUTF32() |
Vorteile
- Wir haben einen konsistenteren API-Satz.
Nachteile
- Abwärtskompatibilität.
- Wir müssen mehr öffentliche APIs für seltene Anwendungsfälle pflegen.
- Die bestehenden öffentlichen APIs reichen für die meisten Anwendungsfälle aus, und
PyUnicode_AsEncodedString()kann in anderen Fällen verwendet werden.
Ersetze Py_UNICODE* durch Py_UCS4*
Wir können Py_UNICODE durch Py_UCS4 ersetzen und diese APIs de-veralten.
UTF-8, UTF-16, UTF-32-Encoder unterstützen intern Py_UCS4. Daher können PyUnicode_EncodeUTF8(), PyUnicode_EncodeUTF16() und PyUnicode_EncodeUTF32() die Erstellung eines temporären Unicode-Objekts vermeiden.
Vorteile
- Wir können die Erstellung eines temporären Unicode-Objekts beim Kodieren von
Py_UCS4*in ein Byte-Objekt mit UTF-8, UTF-16, UTF-32-Codecs vermeiden.
Nachteile
- Abwärtskompatibilität.
- Wir müssen mehr öffentliche APIs für seltene Anwendungsfälle pflegen.
- Andere Python-Implementierungen, die die Python/C-API unterstützen wollen, müssen auch diese APIs unterstützen.
- Wenn wir die interne Darstellung von Unicode in Zukunft auf UTF-8 umstellen, müssen wir die UCS-4-Unterstützung nur für diese APIs beibehalten.
Ersetze Py_UNICODE* durch wchar_t*
Wir können Py_UNICODE durch wchar_t ersetzen. Da Py_UNICODE bereits ein `typedef` von wchar_t ist, ist dies der Status quo.
Auf Plattformen, auf denen sizeof(wchar_t) == 4 ist, können wir die Erstellung eines temporären Unicode-Objekts vermeiden, wenn wir von wchar_t* zu Byte-Objekten mit UTF-8, UTF-16 und UTF-32-Codecs kodieren, ähnlich wie bei der Idee "Ersetze Py_UNICODE* durch Py_UCS4*".
Vorteile
- Abwärtskompatibel.
- Wir können die Erstellung eines temporären Unicode-Objekts vermeiden, wenn wir auf Plattformen, auf denen
sizeof(wchar_t) == 4ist, vonPy_UCS4*in ein Byte-Objekt mit UTF-8, UTF-16, UTF-32-Codecs kodieren.
Nachteile
- Obwohl Windows die wichtigste Plattform ist, die
wchar_tintensiv nutzt, müssen diese APIs immer ein temporäres Unicode-Objekt erstellen, dasizeof(wchar_t) == 2unter Windows ist. - Wir müssen mehr öffentliche APIs für seltene Anwendungsfälle pflegen.
- Andere Python-Implementierungen, die die Python/C-API unterstützen wollen, müssen auch diese APIs unterstützen.
- Wenn wir die interne Darstellung von Unicode in Zukunft auf UTF-8 umstellen, müssen wir die UCS-4-Unterstützung nur für diese APIs beibehalten.
Abgelehnte Ideen
Laufzeitwarnung ausgeben
Zusätzlich zu den bestehenden Compiler-Warnungen wird die Ausgabe einer Laufzeit-DeprecationWarning vorgeschlagen.
Diese APIs geben jedoch derzeit den GIL nicht frei. Die Ausgabe einer Warnung von solchen APIs ist nicht sicher. Siehe dieses Beispiel.
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;
Wenn wir eine Python-Warnung von PyUnicode_EncodeUTF8() ausgeben, können Warnungsfilter und andere Threads die list ändern, und u kann eine hängende Referenz sein, nachdem PyUnicode_EncodeUTF8() zurückgekehrt ist.
Diskussionen
- [python-dev] Plan zur Entfernung von Py_UNICODE-APIs außer PEP 623
- bpo-41123: Entferne Py_UNICODE-APIs außer PEP 623
- [python-dev] PEP 624: Entferne Py_UNICODE-Encoder-APIs
Einwände
- Die Entfernung dieser APIs hebt die Fähigkeit auf, Codecs ohne temporäres Unicode zu verwenden.
- Codecs können keinen Unicode-Puffer direkt ohne ein temporäres Unicode-Objekt kodieren, seit Python 3.3. Alle diese APIs erstellen derzeit temporäre Unicode-Objekte. Daher reduziert die Entfernung keinen Funktionsumfang.
- Warum nicht auch Decoder-APIs entfernen?
- Sie sind Teil der stabilen ABI.
PyUnicode_DecodeASCII()undPyUnicode_DecodeUTF8()werden sehr häufig verwendet. Ihre Verweigerung lohnt sich nicht.- Decoder-APIs können direkt von einem Byte-Puffer dekodieren, ohne ein temporäres Byte-Objekt zu erstellen. Andererseits können Encoder-APIs die Erstellung eines temporären Unicode-Objekts nicht vermeiden.
Referenzen
Urheberrecht
Dieses Dokument wird in die Public Domain oder unter die CC0-1.0-Universal-Lizenz gestellt, je nachdem, welche Lizenz permissiver ist.
Quelle: https://github.com/python/peps/blob/main/peps/pep-0624.rst
Zuletzt geändert: 2025-02-01 08:55:40 GMT