Aus der Python 2.6-Shell:
>>> import sys
>>> print sys.getdefaultencoding()
ascii
>>> print u'\xe9'
é
>>>
Ich habe erwartet, dass nach der print-Anweisung entweder Kauderwelsch oder ein Fehler auftritt, da das Zeichen "é" nicht Teil von ASCII ist und ich keine Codierung angegeben habe. Ich glaube, ich verstehe nicht, was ASCII als Standardcodierung bedeutet.
BEARBEITEN
Ich habe die Bearbeitung in den Bereich Antworten verschoben und sie wie vorgeschlagen akzeptiert.
'\xe9'
in einem für UTF-8 konfigurierten Terminal wird nicht gedruckté
. Es wird ein Ersatzzeichen (normalerweise ein Fragezeichen) gedruckt, da\xe9
es sich nicht um eine gültige UTF-8-Sequenz handelt (es fehlen zwei Bytes, die diesem führenden Byte hätten folgen sollen). Es wird mit Sicherheit nicht stattdessen als Latin-1 interpretiert.\xe9
zum Drucken in ISO-8859-1 (latin1) dekodiert isté
.Antworten:
Ich denke, wir können dank der Kleinigkeiten aus verschiedenen Antworten eine Erklärung zusammenstellen.
Beim Versuch, eine Unicode-Zeichenfolge u '\ xe9' zu drucken, versucht Python implizit, diese Zeichenfolge mit dem derzeit in sys.stdout.encoding gespeicherten Codierungsschema zu codieren. Python übernimmt diese Einstellung tatsächlich aus der Umgebung, aus der es initiiert wurde. Wenn keine ordnungsgemäße Codierung aus der Umgebung gefunden werden kann, wird erst dann die Standardcodierung ASCII wiederhergestellt.
Zum Beispiel verwende ich eine Bash-Shell, deren Codierung standardmäßig UTF-8 ist. Wenn ich Python davon starte, nimmt es diese Einstellung auf und verwendet sie:
Lassen Sie uns für einen Moment die Python-Shell verlassen und die Bash-Umgebung mit einer falschen Codierung festlegen:
Starten Sie dann die Python-Shell erneut und stellen Sie sicher, dass sie tatsächlich zu ihrer Standard-ASCII-Codierung zurückkehrt.
Bingo!
Wenn Sie jetzt versuchen, ein Unicode-Zeichen außerhalb von ASCII auszugeben, sollten Sie eine nette Fehlermeldung erhalten
Beenden wir Python und verwerfen die Bash-Shell.
Wir werden nun beobachten, was passiert, nachdem Python Strings ausgegeben hat. Dazu starten wir zuerst eine Bash-Shell in einem Grafikterminal (ich verwende Gnome Terminal) und stellen das Terminal so ein, dass die Ausgabe mit ISO-8859-1 (auch bekannt als Latin-1) dekodiert wird (Grafikterminals haben normalerweise die Option, Zeichen zu setzen Codierung in einem ihrer Dropdown-Menüs). Beachten Sie, dass dies die Codierung der tatsächlichen Shell-Umgebung nicht ändert , sondern nur die Art und Weise, wie das Terminal selbst die ausgegebene Ausgabe dekodiert, ähnlich wie dies bei einem Webbrowser der Fall ist. Sie können daher die Codierung des Terminals unabhängig von der Shell-Umgebung ändern. Starten wir dann Python von der Shell aus und stellen Sie sicher, dass sys.stdout.encoding auf die Codierung der Shell-Umgebung eingestellt ist (UTF-8 für mich):
(1) Python gibt die Binärzeichenfolge unverändert aus, das Terminal empfängt sie und versucht, ihren Wert mit der Latin-1-Zeichenzuordnung abzugleichen. In Latin-1 ergibt 0xe9 oder 233 das Zeichen "é", und so wird das Terminal angezeigt.
(2) Python versucht, die Unicode-Zeichenfolge implizit mit dem derzeit in sys.stdout.encoding festgelegten Schema zu codieren. In diesem Fall handelt es sich um "UTF-8". Nach der UTF-8-Codierung lautet die resultierende Binärzeichenfolge '\ xc3 \ xa9' (siehe spätere Erläuterung). Das Terminal empfängt den Stream als solchen und versucht, 0xc3a9 mit Latin-1 zu decodieren, aber Latin-1 geht von 0 auf 255 und decodiert daher jeweils nur 1 Byte Streams. 0xc3a9 ist 2 Bytes lang, der Latin-1-Decoder interpretiert es daher als 0xc3 (195) und 0xa9 (169) und ergibt 2 Zeichen: Ã und ©.
(3) Python codiert den Unicode-Codepunkt u '\ xe9' (233) mit dem Latin-1-Schema. Es stellt sich heraus, dass der Bereich für Latin-1-Codepunkte zwischen 0 und 255 liegt und auf genau dasselbe Zeichen wie Unicode in diesem Bereich verweist. Daher ergeben Unicode-Codepunkte in diesem Bereich den gleichen Wert, wenn sie in Latin-1 codiert werden. U '\ xe9' (233), das in Latin-1 codiert ist, ergibt also auch die Binärzeichenfolge '\ xe9'. Das Terminal empfängt diesen Wert und versucht, ihn auf der Latin-1-Zeichenkarte abzugleichen. Genau wie in Fall (1) ergibt es "é" und das wird angezeigt.
Lassen Sie uns nun die Codierungseinstellungen des Terminals aus dem Dropdown-Menü in UTF-8 ändern (so wie Sie die Codierungseinstellungen Ihres Webbrowsers ändern würden). Sie müssen Python nicht stoppen oder die Shell neu starten. Die Codierung des Terminals stimmt jetzt mit der von Python überein. Versuchen wir es noch einmal:
(4) Python gibt eine Binärzeichenfolge unverändert aus. Das Terminal versucht, diesen Stream mit UTF-8 zu dekodieren. UTF-8 versteht den Wert 0xe9 jedoch nicht (siehe spätere Erklärung) und kann ihn daher nicht in einen Unicode-Codepunkt konvertieren. Kein Codepunkt gefunden, kein Zeichen gedruckt.
(5) Python versucht, die Unicode-Zeichenfolge implizit mit den Angaben in sys.stdout.encoding zu codieren. Immer noch "UTF-8". Die resultierende Binärzeichenfolge lautet '\ xc3 \ xa9'. Das Terminal empfängt den Stream und versucht, 0xc3a9 auch mit UTF-8 zu dekodieren. Es ergibt den Rückcodewert 0xe9 (233), der auf der Unicode-Zeichenkarte auf das Symbol "é" zeigt. Terminal zeigt "é" an.
(6) Python codiert eine Unicode-Zeichenfolge mit Latin-1 und liefert eine Binärzeichenfolge mit demselben Wert '\ xe9'. Auch für das Terminal ist dies so ziemlich das Gleiche wie in Fall (4).
Schlussfolgerungen: - Python gibt Nicht-Unicode-Zeichenfolgen als Rohdaten aus, ohne die Standardcodierung zu berücksichtigen. Das Terminal zeigt sie nur an, wenn die aktuelle Codierung mit den Daten übereinstimmt. - Python gibt Unicode-Zeichenfolgen aus, nachdem sie mit dem in sys.stdout.encoding angegebenen Schema codiert wurden. - Python erhält diese Einstellung aus der Umgebung der Shell. - Das Terminal zeigt die Ausgabe gemäß seinen eigenen Codierungseinstellungen an. - Die Codierung des Terminals ist unabhängig von der der Shell.
Weitere Details zu Unicode, UTF-8 und Latin-1:
Unicode ist im Grunde eine Zeichentabelle, in der einige Schlüssel (Codepunkte) herkömmlicherweise zugewiesen wurden, um auf einige Symbole zu verweisen. zB durch Konvention wurde entschieden, dass Schlüssel 0xe9 (233) der Wert ist, der auf das Symbol 'é' zeigt. ASCII und Unicode verwenden dieselben Codepunkte von 0 bis 127 wie Latin-1 und Unicode von 0 bis 255. Das heißt, 0x41 zeigt auf 'A' in ASCII, Latin-1 und Unicode, 0xc8 zeigt auf 'Ü' in Latin-1 und Unicode, 0xe9 zeigt in Latin-1 und Unicode auf 'é'.
Bei der Arbeit mit elektronischen Geräten benötigen Unicode-Codepunkte eine effiziente Möglichkeit, elektronisch dargestellt zu werden. Darum geht es bei Codierungsschemata. Es gibt verschiedene Unicode-Codierungsschemata (utf7, UTF-8, UTF-16, UTF-32). Der intuitivste und einfachste Codierungsansatz wäre, einfach den Wert eines Codepunkts in der Unicode-Karte als Wert für seine elektronische Form zu verwenden. Unicode verfügt derzeit jedoch über mehr als eine Million Codepunkte, was bedeutet, dass einige von ihnen 3 Bytes benötigen ausgedrückt. Um effizient mit Text arbeiten zu können, wäre eine 1: 1-Zuordnung eher unpraktisch, da alle Codepunkte unabhängig von ihrem tatsächlichen Bedarf auf genau demselben Speicherplatz mit mindestens 3 Bytes pro Zeichen gespeichert werden müssten.
Die meisten Codierungsschemata weisen Mängel hinsichtlich des Platzbedarfs auf, die wirtschaftlichsten decken nicht alle Unicode-Codepunkte ab, zum Beispiel deckt ASCII nur die ersten 128 ab, während Latin-1 die ersten 256 abdeckt. Andere, die versuchen, umfassender zu sein, enden ebenfalls verschwenderisch sein, da sie mehr Bytes als nötig benötigen, selbst für übliche "billige" Zeichen. UTF-16 verwendet beispielsweise mindestens 2 Bytes pro Zeichen, einschließlich derjenigen im ASCII-Bereich ('B', das 65 ist, erfordert immer noch 2 Bytes Speicher in UTF-16). UTF-32 ist noch verschwenderischer, da alle Zeichen in 4 Bytes gespeichert werden.
UTF-8 hat das Dilemma mit einem Schema, das Codepunkte mit einer variablen Anzahl von Byte-Leerzeichen speichern kann, geschickt gelöst. Als Teil seiner Codierungsstrategie schnürt UTF-8 Codepunkte mit Flag-Bits, die (vermutlich für Decoder) ihren Platzbedarf und ihre Grenzen angeben.
UTF-8-Codierung von Unicode-Codepunkten im ASCII-Bereich (0-127):
Beispiel: Der Unicode-Codepunkt für 'B' ist '0x42' oder 0100 0010 in Binärform (wie gesagt, es ist dasselbe in ASCII). Nach der Codierung in UTF-8 wird es:
UTF-8-Codierung von Unicode-Codepunkten über 127 (nicht ASCII):
Beispiel: 'é' Unicode-Codepunkt ist 0xe9 (233).
Wenn UTF-8 diesen Wert codiert, wird festgestellt, dass der Wert größer als 127 und kleiner als 2048 ist. Daher sollte er in 2 Byte codiert werden:
Der 0xe9-Unicode-Code zeigt nach der UTF-8-Codierung auf 0xc3a9. Genau so empfängt das Terminal es. Wenn Ihr Terminal so eingestellt ist, dass Zeichenfolgen mit Latin-1 (einer der Nicht-Unicode-Legacy-Codierungen) dekodiert werden, wird à © angezeigt, da 0xc3 in Latin-1 nur auf à und 0xa9 auf © zeigt.
quelle
Wenn Unicode-Zeichen auf Standard gedruckt werden,
sys.stdout.encoding
wird verwendet. Es wird angenommen, dass sich ein Nicht-Unicode-Zeichen in befindet,sys.stdout.encoding
und es wird nur an das Terminal gesendet. Auf meinem System (Python 2):sys.getdefaultencoding()
wird nur verwendet, wenn Python keine andere Option hat.Beachten Sie, dass Python 3.6 oder höher Codierungen unter Windows ignoriert und Unicode-APIs verwendet, um Unicode in das Terminal zu schreiben. Keine UnicodeEncodeError-Warnungen und das richtige Zeichen wird angezeigt, wenn die Schriftart dies unterstützt. Auch wenn die Schriftart dies nicht unterstützt, können die Zeichen vom Terminal in eine Anwendung mit einer unterstützenden Schriftart ausgeschnitten und eingefügt werden, und dies ist korrekt. Aktualisierung!
quelle
Die Python-REPL versucht, die zu verwendende Codierung aus Ihrer Umgebung zu ermitteln. Wenn es etwas Vernünftiges findet, funktioniert alles einfach. Es ist, wenn es nicht herausfinden kann, was los ist, dass es Fehler macht.
quelle
TypeError: readonly attribute
auf 2.7.2Sie haben eine Codierung angegeben, indem Sie eine explizite Unicode-Zeichenfolge eingeben. Vergleichen Sie die Ergebnisse, wenn Sie das
u
Präfix nicht verwenden .In diesem Fall
\xe9
übernimmt Python Ihre Standardcodierung (Ascii) und druckt so ... etwas Leeres.quelle
Für mich geht das:
quelle
Gemäß Python-Standard- / impliziten Zeichenfolgencodierungen und -konvertierungen :
print
ingunicode
, ist esencode
d mit<file>.encoding
.encoding
nicht gesetzt ist, wird dasunicode
implizit in konvertiertstr
(da der Codec dafür istsys.getdefaultencoding()
, dhascii
alle nationalen Zeichen würden a verursachenUnicodeEncodeError
).encoding
aus der Umgebung abgeleitet. Es wird normalerweise fürtty
Streams festgelegt (aus den Gebietsschemaeinstellungen des Terminals), wird jedoch wahrscheinlich nicht für Pipes festgelegtprint u'\xe9'
ist es wahrscheinlich, dass a erfolgreich ist, wenn die Ausgabe an ein Terminal erfolgt, und fehlschlägt, wenn es umgeleitet wird. Eine Lösung besteht darin,encode()
den String vor demprint
Ing mit der gewünschten Codierung zu versehen .print
Ingstr
werden die Bytes unverändert an den Stream gesendet. Welche Glyphen das Terminal anzeigt, hängt von den Ländereinstellungen ab.quelle