Warum unterscheidet sich sys.getdefaultencoding () von sys.stdout.encoding und wie werden Unicode-Strings dadurch unterbrochen?

8

Ich habe ein paar ärgerliche Stunden damit verbracht, nach dem Problem mit Unicode-Strings zu suchen, das in etwas zerlegt wurde, das Python (2.7) vor mir versteckt und das ich immer noch nicht verstehe. Zuerst habe ich versucht, u".." strings konsistent in meinem Code zu verwenden, aber das führte zu dem berüchtigten UnicodeEncodeError . Ich habe versucht mit .encode('utf8') , aber das hat auch nicht geholfen. Schließlich stellte sich heraus, dass ich auch keines benutzen sollte und alles funktioniert automatisch. Wie auch immer, ich (hier muss ich einem Freund, der mir geholfen hat, anerkennen) bemerkte etwas komisches, während ich meinen Kopf gegen die Wand schlug. sys.getdefaultencoding() gibt ascii zurück, während sys.stdout.encoding UTF-8 zurückgibt. 1. im folgenden Code funktioniert gut ohne Änderungen an sys und 2. erhöht UnicodeEncodeError . Wenn ich die Standardsystemcodierung mit reload(sys).setdefaultencoding("utf8") ändere, funktioniert 2. gut. Meine Frage ist, warum die zwei Kodierungsvariablen an erster Stelle anders sind und wie kann ich die falsche Kodierung in diesem einfachen Stück Code verwenden? Bitte, schick mich nicht zum Unicode-HOWTO , das habe ich offensichtlich in den Zehnen gelesen Fragen zu UnicodeEncodeError .

%Vor%     
Aleksandar Savkov 20.03.2013, 17:29
quelle

2 Antworten

4
  

Meine Frage ist, warum die beiden Codierungsvariablen an erster Stelle anders sind

Sie dienen verschiedenen Zwecken.

sys.stdout.encoding sollte die Kodierung sein, die Ihr Terminal benutzt, um Text zu interpretieren, sonst könnten Sie mojibake in der Ausgabe bekommen. Es kann utf-8 in einer Umgebung sein, cp437 in einer anderen, usw.

sys.getdefaultencoding() wird in Python 2 für implizite Konvertierungen verwendet (wenn die Kodierung nicht explizit eingestellt ist), dh Python 2 kann nur ASCII-Bytestrings und Unicode-Strings mischen, zB xml.etree.ElementTree speichert Text im ASCII-Bereich als Bytestrings oder json.dumps() gibt anstelle von Unicode in Python 2 eine ascii-only-Zeichenfolge zurück - möglicherweise aufgrund der Leistung - die Bytes waren billiger als Unicode zum Darstellen von ASCII-Zeichen. Implizite Konvertierungen sind in Python 3 verboten.

sys.getdefaultencoding() ist immer 'ascii' auf allen Systemen in Python 2, außer Sie überschreiben das, was Sie nicht tun sollten, sonst könnte es Fehler verstecken und Ihre Daten könnten leicht beschädigt werden aufgrund der impliziten Konvertierungen mit einer möglicherweise falschen Kodierung für die Daten.

Übrigens gibt es eine andere gängige Kodierung sys.getfilesystemencoding() , die sich von den beiden unterscheiden kann. sys.getfilesystemencoding() sollte die Codierung sein, die zum Verschlüsseln von Betriebssystemdaten verwendet wird (Dateinamen, Befehlszeilenargumente, Umgebungsvariablen).

Die mit # -*- coding: utf-8 -*- deklarierte Quellcodekodierung kann sich von allen bereits erwähnten Codierungen unterscheiden.

Natürlich, wenn Sie Daten aus einer Datei lesen, Netzwerk; es kann Zeichenkodierungen verwenden, die sich von den obigen unterscheiden, z.B. wenn eine in Notepad erstellte Datei unter Verwendung von Windows ANSI-Codierung wie cp1252 gespeichert wird, können auf einem anderen System alle Standardcodierungen davon abweichen.

Der Punkt ist: Es könnte mehrere -Eigenschaften geben, die nicht mit Python zusammenhängen. Um Kopfschmerzen zu vermeiden, verwenden Sie Unicode, um Text darzustellen: konvertieren Sie so bald wie möglich kodierten Text Unicode bei der Eingabe, und codieren Sie es in Bytes (möglicherweise mit einer anderen Codierung) so spät wie möglich bei der Ausgabe - das ist das so genannte Konzept von Unicode-Sandwich .

  

Wie kann ich die falsche Codierung in diesem einfachen Code verwenden?

  1. Ihr erstes Codebeispiel ist nicht in Ordnung. Sie verwenden nicht-ASCII-Literalzeichen in einer Bytezeichenfolge in Python 2, die Sie nicht tun sollten. Verwenden Sie Bytestring-Literale nur für Binärdaten (bei Bedarf auch so genannte native Strings). Der Code erzeugt möglicherweise mojibake wie I need 20 000Γé¼. (beachten Sie das Zeichenrauschen), wenn Sie ihn mit Python 2 in einer Umgebung ausführen, die keine utf-8-kompatible Codierung wie die Windows-Konsole

  2. verwendet
  3. Das zweite Codebeispiel ist ok, wenn man annimmt, dass reload(sys) kein Teil davon ist. Wenn Sie nicht alle Zeichenfolgenliterale mit u'' ; Sie könnten from __future__ import unicode_literals

  4. verwenden

Ihr aktuelles Problem ist UnicodeEncodeError error und reload(sys) ist nicht die richtige Lösung!
Die korrekte Lösung besteht darin, Ihr Gebietsschema in POSIX ( LANG , LC_CTYPE ) oder set PYTHONIOENCODING envvar, wenn die Ausgabe zu einer Pipe / Datei umgeleitet wird oder win-unicode-console installiert wird, um Unicode an die Windows-Konsole zu drucken .

    
jfs 16.11.2015, 00:37
quelle
1

Ich habe das gleiche Verhalten eines Standardcodes (Mailman-Bibliothek) bemerkt. Danke für deine Analyse, es hat mir geholfen etwas Zeit zu sparen. :-) Das Problem ist genau das gleiche. Mein System verwendet sys.getdefaultencoding() und ruft ascii ab, was ungeeignet ist, um eine Liste von 1000 UTF-8-kodierten Namen zu behandeln.

Es gibt eine Diskrepanz zwischen stdin / stdout und sogar Dateisystem-Kodierung (utf-8) einerseits und "defaultencoding" auf der anderen Seite (ascii). Dieser Thread: Wie UTF-8-codiert zu drucken Text zur Konsole in Python & lt; 3? scheint anzuzeigen, dass es sehr bekannt ist und Standardcodierung von Python ändern? enthält einige Hinweise, dass eine homogenere (wie " utf-8 everywhere") andere Dinge wie die Hash-Implementierung unterbrechen würde.

Aus diesem Grund ist es auch nicht einfach, die Defaultencodierung zu ändern. (Siehe Ссылка für verschiedene Möglichkeiten.) Es wird aus der sys -Instanz in% co_de entfernt % Datei.

    
Dirk 14.09.2013 06:29
quelle

Tags und Links