Es ist viel einfacher als Python 2, aber in einigen Umgebungen können in Python 3 unerwartete UnicodeErrors auftreten. Lassen Sie uns die Handhabung verschiedener Python-Codierungen ab Python 3.6 regeln.
filesystem encoding (sys.getfilesystemencoding()
)
Diese Codierung wird hauptsächlich für Dateipfade verwendet, aber auch für Befehlszeilenargumente. (Andernfalls haben Sie Probleme, den Dateipfad als Befehlszeilenargument zu übergeben.)
Da das Gebietsschema verwandt ist, wird es auch bei der Arbeit mit glibc usw. verwendet. Es mag ein Überbleibsel der Python 2-Ära sein, aber jetzt habe ich das Gefühl, dass die Bezeichnung Systemcodierung anstelle von Dateisystemcodierung die Realität darstellt.
preferred encoding (locale.getpreferredencoding()
)
Diese Codierung wird hauptsächlich für den Inhalt von Textdateien verwendet. Es wird verwendet, wenn eine Textdatei mit der Funktion "Öffnen" geöffnet wird.
sys.stdout.encoding
)Die Standard-Eingabe- / Ausgabecodierung ist die Dateisystemcodierung für Terminals und die bevorzugte Codierung für andere, kann jedoch mit der Umgebungsvariablen "PYTHONIOENCODING" geändert werden.
default encoding (sys.getdefaultencoding()
)
Dies ist die Standardcodierung, die verwendet wird, wenn Sie beim Konvertieren zwischen einer Unicode-Zeichenfolge ( str
) und einer Zeichenfolge von Bytes ( Bytes
) keine explizite Codierung angeben. In Python 3 ist UTF-8 unabhängig von der Umgebung vollständig behoben.
>>> "Hallo".encode()
b'\xe3\x81\x93\xe3\x82\x93\xe3\x81\xab\xe3\x81\xa1\xe3\x81\xaf'
>>> _.decode()
'Hallo'
Es war ASCII in der Python 2-Ära, und es gab eine implizite Typkonvertierung, so dass es tendenziell zu Problemen führte. (Es gab auch einen Hack, um utf-8 zu zwingen, eine App auszuführen, die nicht an Multibyte dachte.)
Python 3 führt keine implizite Typkonvertierung zwischen str und bytes durch, daher ist es nur ein Standardargument. Sie können die Existenz selbst vergessen.
macOS, android
Da es auf Betriebssystemebene auf UTF-8 festgelegt ist, lautet die Dateisystemcodierung immer UTF-8.
Die bevorzugte Codierung ist immer UTF-8 für Android festgelegt und kann mit dem Gebietsschema für macOS geändert werden, aber ich denke, dass dies selten ein Problem ist. (Wenn das Gebietsschema festgelegt ist, entspricht es dem später beschriebenen Linux.)
Windows
Da Windows W-basierte APIs sowohl beim Öffnen von Dateien als auch beim Empfangen von Befehlszeilenargumenten verwendet, wird die Dateisystemcodierung selten verwendet.
Das Verhalten beim Umgang mit Dateipfaden als Bytezeichenfolgen war die aktuelle Codepage "cp932", da es sich bis Python 3.5 um einen Windows A-API-Aufruf handelte. Ab Python 3.6 hat sich dieses Verhalten geändert und UTF-8 => UTF-16-Konvertierung und W-basierte APIs werden verwendet, sodass die Dateisystemcodierung "utf-8" lautet. (Es gibt auch Umgebungsvariablen, die auf das Verhalten von Python 3.5 zurückgesetzt werden können.)
Die bevorzugte Codierung verwendet andererseits immer noch die Codepage. Es ist ein Vermächtnis, bis Microsoft die Standard-Textdatei für UTF-8 erstellt. Es tut mir Leid.
Am enttäuschendsten ist das andere Unix. Dies hängt vom Gebietsschema ab ( LC_CTYPE
). Wenn noch jemand "LANG = ja_JP.eucJP" sagt, ist sowohl die Dateisystemcodierung als auch die bevorzugte Codierung EUC-JP. Wenn Sie eine Textdatei in UTF-8 erstellen möchten, geben Sie die Codierung explizit mit der Funktion "Öffnen" für Umgebungen an, in denen das Gebietsschema nicht UTF-8 ist, auch wenn Sie Windows überhaupt nicht unterstützen möchten.
Die Abhängigkeit vom Gebietsschema ist besonders enttäuschend, da die Standardcodierung (C oder POSIX) (LC_CTYPE) für das Gebietsschema standardmäßig ASCII ist.
Einige Benutzer verwenden das Gebietsschema C oder POSIX, weil ihnen das Verhalten verschiedener Befehle wie Sortieren je nach Gebietsschema nicht gefällt. Integrierte oder Container-Images verfügen möglicherweise nicht über die Gebietsschemas en_US.utf8 oder ja_JP.utf8, um Gewicht zu sparen. Wenn Sie ssh von einem Mac ausführen (weil die Umgebungsvariable LANG gesendet wird), wird möglicherweise eine Fehlermeldung angezeigt und Sie greifen auf C zurück, wenn Sie versuchen, ja_JP.UTF-8 unter Linux zu verwenden, das nur en_US.UTF-8 enthält. Zu diesem Zeitpunkt befindet sich Python vollständig im ASCII-Modus.
$ export LC_ALL=C
$ echo 'print("Hallo\n")' > hello
$ ruby hello
Hallo
$ perl hello
Hallo
$ python3 hello
Traceback (most recent call last):
File "hello", line 1, in <module>
print("\u3053\u3093\u306b\u3061\u306f\n")
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-4: ordinal not in range(128)
Wenn die Dateisystemcodierung ASCII bleiben kann, können Sie die Standardeingabe- / Ausgabecodierung mit PYTHONIOENCODING angeben, ohne das Gebietsschema festzulegen. Schreiben Sie es in .bashrc oder crontab.
$ PYTHONIOENCODING=utf-8 python3 hello
Hallo
Das erste, woran Sie sich erinnern sollten, ist der Befehl locale
, mit dem das aktuelle Gebietsschema angezeigt wird, und der Befehl locale -a
, mit dem eine Liste der verfügbaren Gebietsschemas angezeigt wird.
$ locale
LANG=C.UTF-8
LANGUAGE=en_US:en
LC_CTYPE="C.UTF-8"
LC_NUMERIC="C.UTF-8"
LC_TIME="C.UTF-8"
LC_COLLATE="C.UTF-8"
LC_MONETARY="C.UTF-8"
LC_MESSAGES="C.UTF-8"
LC_PAPER="C.UTF-8"
LC_NAME="C.UTF-8"
LC_ADDRESS="C.UTF-8"
LC_TELEPHONE="C.UTF-8"
LC_MEASUREMENT="C.UTF-8"
LC_IDENTIFICATION="C.UTF-8"
LC_ALL=
$ locale -a
C
C.UTF-8
POSIX
en_US.utf8
Ich denke, C.UTF-8 ist in modernem Linux enthalten. Eine UTF-8-Version des C-Gebietsschemas, die nichts Besonderes bewirkt. Es ist perfekt für Benutzer, die das Gebietsschema C verwenden möchten, aber UTF-8-Dateinamen verwenden möchten. Wenn es nicht vorhanden ist, sollten Sie es mit "sudo localedef -c -i POSIX -f UTF-8 C.UTF-8" erstellen können, wenn Sie über Root-Rechte verfügen.
Wenn ja_JP.UTF-8 oder en_US.UTF-8 vorhanden ist und Sie es verwenden möchten, legen Sie es in der Umgebungsvariablen LANG fest und überprüfen Sie es mit dem Befehl locale.
$ export LANG=en_US.utf8
$ locale
LANG=en_US.utf8
LANGUAGE=en_US:en
LC_CTYPE="en_US.utf8"
LC_NUMERIC="en_US.utf8"
LC_TIME="en_US.utf8"
LC_COLLATE="en_US.utf8"
LC_MONETARY="en_US.utf8"
LC_MESSAGES="en_US.utf8"
LC_PAPER="en_US.utf8"
LC_NAME="en_US.utf8"
LC_ADDRESS="en_US.utf8"
LC_TELEPHONE="en_US.utf8"
LC_MEASUREMENT="en_US.utf8"
LC_IDENTIFICATION="en_US.utf8"
LC_ALL=
Ich möchte das Gebietsschema C verwenden! Aber ich möchte UTF-8 verwenden! Aber ich kann C.UTF-8 nicht machen! Lassen Sie es uns in diesem Fall etwas genauer steuern.
Von jedem LC_XXXXX ist derjenige, den Python zur Bestimmung der Codierung verwendet, "LC_CTYPE".
Die Umgebungsvariable LANG
setzt den gesamten LC_XXXX mit Ausnahme von LC_ALL
und kann mit jedem LC_XXXX einzeln überschrieben werden. Wenn jedoch LC_ALL
gesetzt ist, wird alles weiter überschrieben.
Sie können LC_CTYPE also auf ein UTF-8-Gebietsschema setzen, während Sie LANG = C setzen.
$ export LANG=C
$ export LC_CTYPE=en_US.UTF-8
$ locale
LANG=C
LANGUAGE=en_US:en
LC_CTYPE=en_US.UTF-8
LC_NUMERIC="C"
LC_TIME="C"
LC_COLLATE="C"
LC_MONETARY="C"
LC_MESSAGES="C"
LC_PAPER="C"
LC_NAME="C"
LC_ADDRESS="C"
LC_TELEPHONE="C"
LC_MEASUREMENT="C"
LC_IDENTIFICATION="C"
LC_ALL=
$ locale charmap
UTF-8
$ python3 -c 'import sys; print(sys.getfilesystemencoding())'
utf-8
Recommended Posts