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

Python Enhancement Proposals

PEP 540 – Hinzufügen eines neuen UTF-8-Modus

Autor:
Victor Stinner <vstinner at python.org>
BDFL-Delegate:
INADA Naoki
Status:
Final
Typ:
Standards Track
Erstellt:
05-Jan-2016
Python-Version:
3.7
Resolution:
Python-Dev Nachricht

Inhaltsverzeichnis

Zusammenfassung

Fügen Sie einen neuen „UTF-8-Modus“ hinzu, um die Verwendung von UTF-8 durch Python zu verbessern. Wenn der UTF-8-Modus aktiv ist, wird Python

  • die utf-8-Kodierung verwenden, unabhängig von der aktuell von der aktuellen Plattform gesetzten Locale, und
  • die Fehlerbehandler für stdin und stdout auf surrogateescape ändern.

Dieser Modus ist standardmäßig deaktiviert, wird aber automatisch aktiviert, wenn die „POSIX“-Locale verwendet wird.

Fügen Sie die Kommandozeilenoption -X utf8 und die Umgebungsvariable PYTHONUTF8 hinzu, um den UTF-8-Modus zu steuern.

Begründung

Locale-Encoding und UTF-8

Python 3.6 verwendet die Locale-Kodierung für Dateinamen, Umgebungsvariablen, Standardströme usw. Die Locale-Kodierung wird von der Locale geerbt; die Kodierung und die Locale sind eng miteinander verknüpft.

Viele Benutzer erben die ASCII-Kodierung von der POSIX-Locale, auch bekannt als „C“-Locale, können aber die Locale aus verschiedenen Gründen nicht ändern. Diese Kodierung ist in Bezug auf die Unicode-Unterstützung sehr begrenzt: jedes Nicht-ASCII-Zeichen wird wahrscheinlich Probleme verursachen.

Es ist nicht immer einfach, eine genaue Locale zu erhalten. Locales haben auf verschiedenen Linux-Distributionen, FreeBSD, macOS usw. nicht genau den gleichen Namen. Und einige Locales, wie die neuere C.UTF-8-Locale, werden nur von wenigen Plattformen unterstützt. Die aktuelle Locale kann sogar auf derselben Plattform je nach Kontext variieren; zum Beispiel kann eine SSH-Verbindung eine andere Kodierung als das Dateisystem oder die lokale Terminalkodierung auf derselben Maschine verwenden.

Auf der anderen Seite verwendet Python 3.6 unter macOS, Android und Windows (PEP 529) für die meisten Funktionen bereits standardmäßig UTF-8 – obwohl open() hier eine bemerkenswerte Ausnahme darstellt. UTF-8 ist auch die Standardkodierung von Python-Skripten, XML- und JSON-Dateiformaten. Die Programmiersprache Go verwendet UTF-8 für alle Zeichenfolgen.

Die UTF-8-Unterstützung ist für Daten, die von modernen Plattformen gelesen und geschrieben werden, fast universell. Sie hat auch exzellente Unterstützung in Python. Das Problem ist einfach, dass die Locale häufig falsch konfiguriert ist. Eine offensichtliche Lösung drängt sich auf: Ignorieren Sie die Locale-Kodierung und verwenden Sie UTF-8.

Weiterleitung für nicht dekodierbare Bytes: surrogateescape

Beim Dekodieren von Bytes aus UTF-8 mit dem Standardfehlerhandler strict löst Python 3 beim ersten nicht dekodierbaren Byte einen UnicodeDecodeError aus.

Unix-Kommandozeilenwerkzeuge wie cat oder grep und die meisten Python-2-Anwendungen haben diese Art von Fehlern einfach nicht: Sie dekodieren keine Daten, sondern verarbeiten Daten als rohe Byte-Sequenz.

Python 3 verfügt bereits über eine Lösung, um sich wie Unix-Tools und Python 2 zu verhalten: den Fehlerhandler surrogateescape (PEP 383). Er erlaubt die Verarbeitung von Daten, als wären sie Bytes, verwendet aber tatsächlich Unicode; nicht dekodierbare Bytes werden als Surrogatzeichen gespeichert.

Der UTF-8-Modus setzt den Fehlerhandler surrogateescape für stdin und stdout, da diese Ströme üblicherweise mit Unix-Kommandozeilenwerkzeugen verbunden sind.

Benutzer haben jedoch eine andere Erwartung an Dateien. Es wird erwartet, dass Dateien ordnungsgemäß kodiert sind, und es wird erwartet, dass Python frühzeitig fehlschlägt, wenn open() mit den falschen Optionen aufgerufen wird, z. B. das Öffnen eines JPEG-Bildes im Textmodus. Der Standardfehlerhandler von open() bleibt aus diesen Gründen strict.

Standardmäßig keine Änderung zur besten Abwärtskompatibilität

Obwohl UTF-8 in den meisten Fällen perfekt ist, ist die Locale-Kodierung manchmal tatsächlich die beste Kodierung.

Dieser PEP ändert das Verhalten für die POSIX-Locale, da diese Locale normalerweise der ASCII-Kodierung entspricht, während UTF-8 eine viel bessere Wahl ist. Er ändert das Verhalten für andere Locales nicht, um jegliches Risiko oder Rückschritt zu vermeiden.

Da die Benutzer dafür verantwortlich sind, den neuen UTF-8-Modus für diese anderen Locales explizit zu aktivieren, sind sie für alle potenziellen Mojibake-Probleme verantwortlich, die durch den UTF-8-Modus verursacht werden.

Vorschlag

Fügen Sie einen neuen UTF-8-Modus hinzu, um die UTF-8-Kodierung zu verwenden, die Locale-Kodierung zu ignorieren und die Fehlerbehandler für stdin und stdout auf surrogateescape zu ändern.

Fügen Sie die neue Kommandozeilenoption -X utf8 und die Umgebungsvariable PYTHONUTF8 hinzu. Benutzer können den UTF-8-Modus explizit mit der Kommandozeilenoption -X utf8 oder durch Setzen der Umgebungsvariable PYTHONUTF8=1 aktivieren.

Dieser Modus ist standardmäßig deaktiviert und wird von der POSIX-Locale aktiviert. Benutzer können den UTF-8-Modus explizit mit der Kommandozeilenoption -X utf8=0 oder durch Setzen der Umgebungsvariable PYTHONUTF8=0 deaktivieren.

Für Standardströme hat die Umgebungsvariable PYTHONIOENCODING Vorrang vor dem UTF-8-Modus.

Unter Windows hat die Umgebungsvariable PYTHONLEGACYWINDOWSFSENCODING (PEP 529) Vorrang vor dem UTF-8-Modus.

Auswirkungen des UTF-8-Modus

  • sys.getfilesystemencoding() gibt 'UTF-8' zurück.
  • locale.getpreferredencoding() gibt UTF-8 zurück; das Argument do_setlocale und die Locale-Kodierung werden ignoriert.
  • Der Fehlerhandler für sys.stdin und sys.stdout wird auf surrogateescape gesetzt.

Nebeneffekte

  • open() verwendet standardmäßig die UTF-8-Kodierung. Es verwendet jedoch standardmäßig immer noch den Fehlerhandler strict.
  • os.fsdecode() und os.fsencode() verwenden die UTF-8-Kodierung.
  • Kommandozeilenargumente, Umgebungsvariablen und Dateinamen verwenden die UTF-8-Kodierung.

Beziehung zur Locale-Koerzession (PEP 538)

Die POSIX-Locale aktiviert die Locale-Koerzession (PEP 538) und den UTF-8-Modus (PEP 540). Wenn die Locale-Koerzession aktiviert ist, hat die Aktivierung des UTF-8-Modus keine zusätzlichen Auswirkungen.

Der UTF-8-Modus hat die gleiche Auswirkung wie die Locale-Koerzession

  • sys.getfilesystemencoding() gibt 'UTF-8' zurück,
  • locale.getpreferredencoding() gibt UTF-8 zurück, und
  • die Fehlerbehandler für sys.stdin und sys.stdout werden auf surrogateescape gesetzt.

Diese Änderungen wirken sich nur auf Python-Code aus. Die Locale-Koerzession hat jedoch zusätzliche Auswirkungen: die Umgebungsvariable LC_CTYPE und die Locale LC_CTYPE werden auf eine UTF-8-Locale wie C.UTF-8 gesetzt. Eine Nebenwirkung ist, dass Nicht-Python-Code ebenfalls von der Locale-Koerzession betroffen ist. Die beiden PEPs ergänzen sich.

Auf Plattformen wie Centos 7, wo die Locale-Koerzession nicht unterstützt wird, aktiviert die POSIX-Locale nur den UTF-8-Modus. In diesem Fall verwendet Python-Code die UTF-8-Kodierung und ignoriert die Locale-Kodierung, während Nicht-Python-Code die Locale-Kodierung verwendet, die für die POSIX-Locale normalerweise ASCII ist.

Während der UTF-8-Modus auf allen Plattformen unterstützt wird und mit jeder Locale aktiviert werden kann, wird die Locale-Koerzession nicht von allen Plattformen unterstützt und ist auf die POSIX-Locale beschränkt.

Der UTF-8-Modus hat nur Auswirkungen auf Python-Kindprozesse, wenn die Umgebungsvariable PYTHONUTF8 auf 1 gesetzt ist, während die Locale-Koerzession die Umgebungsvariablen LC_CTYPE setzt, was alle Kindprozesse betrifft.

Der Vorteil des Locale-Koerzessionsansatzes besteht darin, dass er dazu beiträgt, dass die Kodierungsbehandlung in binären Erweiterungsmodulen und Kindprozessen mit der Kodierungsbehandlung von Python konsistent ist. Der Vorteil des UTF-8-Modusansatzes besteht darin, dass er es einer eingebetteten Anwendung ermöglicht, das Verhalten des Interpreters zu ändern, ohne die globalen Locale-Einstellungen des Prozesses ändern zu müssen.

Abwärtskompatibilität

Die einzige rückwärts inkompatible Änderung besteht darin, dass die POSIX-Locale jetzt standardmäßig den UTF-8-Modus aktiviert: sie verwendet nun die UTF-8-Kodierung, ignoriert die Locale-Kodierung und ändert die Fehlerbehandler für stdin und stdout auf surrogateescape.

Anhang: Encodings und Fehlerbehandler

Der UTF-8-Modus ändert die Standardkodierung und den Standardfehlerhandler, die von open(), os.fsdecode(), os.fsencode(), sys.stdin, sys.stdout und sys.stderr verwendet werden.

Encoding und Fehlerbehandler

Funktion Standard UTF-8-Modus oder POSIX-Locale
open() locale/strict UTF-8/strict
os.fsdecode(), os.fsencode() locale/surrogateescape UTF-8/surrogateescape
sys.stdin, sys.stdout locale/strict UTF-8/surrogateescape
sys.stderr locale/backslashreplace UTF-8/backslashreplace

Zum Vergleich, Python 3.6 verwendet

Funktion Standard POSIX-Locale
open() locale/strict locale/strict
os.fsdecode(), os.fsencode() locale/surrogateescape locale/surrogateescape
sys.stdin, sys.stdout locale/strict locale/surrogateescape
sys.stderr locale/backslashreplace locale/backslashreplace

Encoding und Fehlerbehandler unter Windows

Unter Windows sind die Kodierungen und Fehlerbehandler unterschiedlich

Funktion Standard Legacy Windows FS-Kodierung UTF-8-Modus
open() mbcs/strict mbcs/strict UTF-8/strict
os.fsdecode(), os.fsencode() UTF-8/surrogatepass mbcs/replace UTF-8/surrogatepass
sys.stdin, sys.stdout UTF-8/surrogateescape UTF-8/surrogateescape UTF-8/surrogateescape
sys.stderr UTF-8/backslashreplace UTF-8/backslashreplace UTF-8/backslashreplace

Zum Vergleich, Python 3.6 verwendet

Funktion Standard Legacy Windows FS-Kodierung
open() mbcs/strict mbcs/strict
os.fsdecode(), os.fsencode() UTF-8/surrogatepass mbcs/replace
sys.stdin, sys.stdout UTF-8/surrogateescape UTF-8/surrogateescape
sys.stderr UTF-8/backslashreplace UTF-8/backslashreplace

Die „Legacy Windows FS-Kodierung“ wird durch die Umgebungsvariable PYTHONLEGACYWINDOWSFSENCODING aktiviert.

Wenn stdin und/oder stdout an eine Pipe umgeleitet werden, verwenden sys.stdin und/oder sys.stdout standardmäßig die mbcs-Kodierung anstelle von UTF-8. Aber im UTF-8-Modus verwenden sys.stdin und sys.stdout immer die UTF-8-Kodierung.

Hinweis

Unter Windows gibt es keine POSIX-Locale. Die ANSI-Codepage wird als Locale-Kodierung verwendet, und diese Codepage verwendet niemals die ASCII-Kodierung.

Post-Historie

Versionshistorie

  • Version 4: locale.getpreferredencoding() gibt im UTF-8-Modus nun 'UTF-8' zurück.
  • Version 3: Der UTF-8-Modus ändert den Standardfehlerhandler von open() (strict) nicht mehr, und der Strict UTF-8-Modus wurde entfernt.
  • Version 2: Überarbeitung des PEP von Grund auf, um ihn viel kürzer und leichter verständlich zu machen.
  • Version 1: Erste Version, die an python-dev gepostet wurde.

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

Zuletzt geändert: 2025-02-01 08:59:27 GMT