Following system colour scheme Selected dark colour scheme Selected light colour scheme

Python Enhancement Proposals

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

Inhaltsverzeichnis

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

  1. Der Parameter const char *errors fehlt.
  2. Es gibt keine öffentliche alternative API. Aber Benutzer können stattdessen die generische PyUnicode_AsEncodedString() verwenden.
  3. Die Parameter const char *errors, int byteorder fehlen.
  4. Es gibt keinen direkten Ersatz. Aber Py_UNICODE_TODECIMAL kann stattdessen verwendet werden. CPython verwendet _PyUnicode_TransformDecimalAndSpaceToASCII zur 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) == 4 ist, von Py_UCS4* in ein Byte-Objekt mit UTF-8, UTF-16, UTF-32-Codecs kodieren.

Nachteile

  • Obwohl Windows die wichtigste Plattform ist, die wchar_t intensiv nutzt, müssen diese APIs immer ein temporäres Unicode-Objekt erstellen, da sizeof(wchar_t) == 2 unter 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

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() und PyUnicode_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


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

Zuletzt geändert: 2025-02-01 08:55:40 GMT