Wie ist das nicht ein genaues Duplikat der Gefahren von sys.setdefaultencoding ('utf-8') ? Obwohl diese (2010) Frage älter ist als diese (2015)? Aber diese Frage hat auch gute Antworten. Was ist zu tun? Um klar zu sein, macht diese Frage nur in Python 2 Sinn, nicht in 3, aber das ist nirgends markiert oder erwähnt.
Gemäß Dokumentation: Auf diese Weise können Sie vom Standard-ASCII zu anderen Codierungen wie UTF-8 wechseln, die die Python-Laufzeit immer dann verwendet, wenn ein Zeichenfolgenpuffer in Unicode dekodiert werden muss.
Diese Funktion ist nur beim Start von Python verfügbar, wenn Python die Umgebung scannt. Es muss in einem systemweiten Modul aufgerufen werden. sitecustomize.pyNachdem dieses Modul ausgewertet wurde, wird die setdefaultencoding()Funktion aus dem sysModul entfernt.
Die einzige Möglichkeit, es tatsächlich zu verwenden, ist ein Reload-Hack, der das Attribut zurückbringt.
Auch von der Verwendung von sys.setdefaultencoding()wurde immer abgeraten , und es ist in py3k ein No-Op geworden. Die Codierung von py3k ist fest mit "utf-8" verbunden, und das Ändern dieser Codierung führt zu einem Fehler.
Ich möchte hinzufügen, dass die Standardcodierung auch für die Codierung verwendet wird (beim Schreiben in sys.stdouteine NoneCodierung, z. B. beim Umleiten der Ausgabe eines Python-Programms).
Eric O Lebigot
14
+1 für "die Verwendung von sys.setdefaultencoding()wurde immer entmutigt"
jfs
7
'fest mit utf-8 verbunden' ist nicht wahr, es ist nicht fest verdrahtet und es ist nicht immer UTF-8. LC_ALL=en_US.UTF-8 python3 -c 'import sys; print(sys.stdout.encoding)'gibt UTF-8aber LC_ALL=C python3 -c 'import sys; print(sys.stdout.encoding)'gibt ANSI_X3.4-1968(oder vielleicht etwas anderes)
Tino
7
@Tino, die Konsolencodierung unterscheidet sich von der Standardcodierung.
Alastair McCormack
58
tl; dr
Die Antwort ist NIE ! (es sei denn, Sie wissen wirklich, was Sie tun)
Das 9/10-fache der Lösung kann mit einem angemessenen Verständnis der Codierung / Decodierung gelöst werden.
1/10 Personen haben ein falsch definiertes Gebietsschema oder eine falsch definierte Umgebung und müssen Folgendes festlegen:
PYTHONIOENCODING="UTF-8"
in ihrer Umgebung, um Konsolendruckprobleme zu beheben.
Was tut es?
sys.setdefaultencoding("utf-8")(durchgestrichen, um eine Wiederverwendung zu vermeiden) Ändert die Standardcodierung / -decodierung, die verwendet wird, wenn Python 2.x einen Unicode () in einen str () konvertieren muss (und umgekehrt) und die Codierung nicht angegeben wird. Dh:
str(u"\u20AC")
unicode("€")"{}".format(u"\u20AC")
In Python 2.x ist die Standardcodierung auf ASCII festgelegt, und die obigen Beispiele schlagen fehl mit:
UnicodeDecodeError:'ascii' codec can't decode byte 0xe2 in position 0: ordinal not in range(128)
(Meine Konsole ist als UTF-8 konfiguriert "€" = '\xe2\x82\xac', daher Ausnahme auf \xe2)
oder
UnicodeEncodeError:'ascii' codec can't encode character u'\u20ac' in position 0: ordinal not in range(128)
sys.setdefaultencoding("utf-8")wird zulassen, dass diese für mich funktionieren , aber nicht unbedingt für Leute, die UTF-8 nicht verwenden. Die Standardeinstellung von ASCII stellt sicher, dass Annahmen zur Codierung nicht in Code eingebettet werden
Konsole
sys.setdefaultencoding("utf-8")hat auch den Nebeneffekt sys.stdout.encoding, dass es beim Drucken von Zeichen auf die Konsole angezeigt wird. Python verwendet das Gebietsschema des Benutzers (Linux / OS X / Un * x) oder die Codepage (Windows), um dies festzulegen. Gelegentlich ist das Gebietsschema eines Benutzers fehlerhaft und es muss nur PYTHONIOENCODINGdie Konsolencodierung korrigiert werden .
Beispiel:
$ export LANG=en_GB.gibberish
$ python
>>> import sys
>>> sys.stdout.encoding
'ANSI_X3.4-1968'
>>> print u"\u20AC"
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode character u'\u20ac' in position 0: ordinal not in range(128)
>>> exit()
$ PYTHONIOENCODING=UTF-8 python
>>> import sys
>>> sys.stdout.encoding
'UTF-8'
>>> print u"\u20AC"
€
Was ist so schlimm an sys.setdefaultencoding ("utf-8") ?
Die Leute entwickeln seit 16 Jahren gegen Python 2.x mit dem Verständnis, dass die Standardcodierung ASCII ist. UnicodeErrorEs wurden Ausnahmebehandlungsmethoden geschrieben, um die Konvertierung von Zeichenfolgen in Unicode für Zeichenfolgen zu verarbeiten, die Nicht-ASCII enthalten.
def welcome_message(byte_string):try:return u"%s runs your business"% byte_string
exceptUnicodeError:return u"%s runs your business"% unicode(byte_string,
encoding=detect_encoding(byte_string))print(welcome_message(u"Angstrom (Å®)".encode("latin-1"))
Vor dem Festlegen der Standardcodierung konnte dieser Code das „Å“ in der ASCII-Codierung nicht dekodieren und gab dann den Ausnahmehandler ein, um die Codierung zu erraten und sie ordnungsgemäß in Unicode umzuwandeln. Drucken: Angstrom (Å®) führt Ihr Unternehmen. Sobald Sie die Standardcodierung auf utf-8 gesetzt haben, stellt der Code fest, dass der byte_string als utf-8 interpretiert werden kann. Dadurch werden die Daten entstellt und stattdessen zurückgegeben: Angstrom (Ů) führt Ihr Unternehmen aus.
Das Ändern einer Konstanten hat dramatische Auswirkungen auf die Module, von denen Sie abhängig sind. Es ist besser, nur die Daten zu korrigieren, die in Ihren Code ein- und ausgehen.
Es gibt zwar Überraschungen sys.setdefaultencoding("utf-8"), aber es ist gut, den Code eher wie Python 3 zu verhalten. Es ist jetzt 2017. Selbst als Sie die Antwort im Jahr 2015 geschrieben haben, war es meiner Meinung nach schon besser, vorwärts als rückwärts zu schauen. Es war tatsächlich die einfachste Lösung für mich, als ich feststellte, dass sich mein Code in Python 2 unterschiedlich verhält, je nachdem, ob die Ausgabe umgeleitet wird (sehr unangenehmes Problem für Python 2). Unnötig zu # coding: utf-8erwähnen , dass ich dies bereits getan habe und keine Problemumgehungen für Python 3 benötige (ich muss die setdefaultencodingÜberprüfung der verwendeten Version tatsächlich maskieren ).
Yongwei Wu
Das ist großartig und funktioniert für Sie, sys.setdefaultencoding("utf-8")macht Ihren Py 2.x-Code jedoch nicht mit Python 3 kompatibel. Es werden auch keine externen Module repariert, bei denen davon ausgegangen wird, dass die Standardcodierung ASCII ist. Die Kompatibilität Ihres Codes mit Python 3 ist sehr einfach und erfordert diesen bösen Hack nicht. Zum Beispiel, warum dies sehr reale Probleme verursacht, siehe meine Erfahrung mit Amazon, die mit dieser Annahme herumspielt
Alastair McCormack
1
@AlastairMcCormack du rockst, meine Seite ist seit Monaten und konnte nicht herausfinden, was zu tun ist. Schließlich PYTHONIOENCODING="UTF-8"half meine Python2.7 Django-1.11-Umgebung. Vielen Dank.
Sam
Ich weiß, dass Sie das Beispiel kopiert haben, aber ich kann herausfinden, welches Paket enthält detect_encoding.
Dlamblin
@dlamblin Das Codebeispiel dient zum Nachweis des Zitats und darf nicht in Ihrem Code verwendet werden. Stellen Sie sich vor, dies detect_encodingist eine Methode, mit der die Codierung einer Zeichenfolge anhand von Sprachhinweisen erkannt werden kann.
Alastair McCormack
18
#!/usr/bin/env python#-*- coding: utf-8 -*-
u = u'moçambique'print u.encode("utf-8")print u
chmod +x test.py
./test.py
moçambique
moçambique
./test.py > output.txt
Traceback(most recent call last):File"./test.py", line 5,in<module>print u
UnicodeEncodeError:'ascii' codec can't encode character
u'\xe7' in position 2: ordinal not in range(128)
Bei Shell funktioniert das Senden an sdtout nicht, das ist also eine Problemumgehung, um an stdout zu schreiben.
Ich habe einen anderen Ansatz gewählt, der nicht ausgeführt wird, wenn sys.stdout.encoding nicht definiert ist oder mit anderen Worten, zuerst PYTHONIOENCODING = UTF-8 exportiert werden muss, um in stdout zu schreiben.
import sys
if(sys.stdout.encoding isNone):print>> sys.stderr,"please set python env PYTHONIOENCODING=UTF-8, example: export PYTHONIOENCODING=UTF-8, when write to stdout."
exit(1)
Dies beantwortet die gestellte Frage nicht. Eher einige tangentiale Gedanken zu diesem Thema.
ivan_pozdeev
3
Die erste Gefahr liegt in reload(sys).
Wenn Sie ein Modul neu laden, erhalten Sie in Ihrer Laufzeit tatsächlich zwei Kopien des Moduls. Das alte Modul ist wie alles andere ein Python-Objekt und bleibt am Leben, solange Verweise darauf vorhanden sind. Die Hälfte der Objekte zeigt also auf das alte Modul und die Hälfte auf das neue. Wenn Sie Änderungen vornehmen, werden Sie diese nie sehen, wenn ein zufälliges Objekt die Änderung nicht sieht:
(ThisisIPython shell)In[1]:import sys
In[2]: sys.stdout
Out[2]:<colorama.ansitowin32.StreamWrapper at 0x3a2aac8>In[3]: reload(sys)<module 'sys'(built-in)>In[4]: sys.stdout
Out[4]:<open file '<stdout>', mode 'w' at 0x00000000022E20C0>In[11]:importIPython.terminal
In[14]:IPython.terminal.interactiveshell.sys.stdout
Out[14]:<colorama.ansitowin32.StreamWrapper at 0x3a9aac8>
Möglicherweise gibt es Code, der davon abhängt, UnicodeErrordass er für Nicht-ASCII-Eingaben ausgegeben wird, oder die Transcodierung mit einem Fehlerhandler, der jetzt ein unerwartetes Ergebnis erzeugt. Und da der gesamte Code mit der Standardeinstellung getestet wird, befinden Sie sich hier ausschließlich auf "nicht unterstütztem" Gebiet , und niemand gibt Ihnen Garantien für das Verhalten des Codes.
Die Transcodierung kann zu unerwarteten oder unbrauchbaren Ergebnissen führen, wenn nicht alles auf dem System UTF-8 verwendet, da Python 2 tatsächlich mehrere unabhängige "Standard-String-Codierungen" hat . (Denken Sie daran, dass ein Programm für den Kunden auf der Ausrüstung des Kunden funktionieren muss.)
Das Schlimmste ist wiederum , dass Sie das nie erfahren werden, da die Konvertierung implizit ist - Sie wissen nicht wirklich, wann und wo sie stattfindet. (Python Zen, koan 2 ahoi!) Sie werden nie wissen, warum (und ob) Ihr Code auf einem System funktioniert und auf einem anderen kaputt geht. (Oder noch besser, funktioniert in IDE und bricht in der Konsole.)
Antworten:
Gemäß Dokumentation: Auf diese Weise können Sie vom Standard-ASCII zu anderen Codierungen wie UTF-8 wechseln, die die Python-Laufzeit immer dann verwendet, wenn ein Zeichenfolgenpuffer in Unicode dekodiert werden muss.
Diese Funktion ist nur beim Start von Python verfügbar, wenn Python die Umgebung scannt. Es muss in einem systemweiten Modul aufgerufen werden.
sitecustomize.py
Nachdem dieses Modul ausgewertet wurde, wird diesetdefaultencoding()
Funktion aus demsys
Modul entfernt.Die einzige Möglichkeit, es tatsächlich zu verwenden, ist ein Reload-Hack, der das Attribut zurückbringt.
Auch von der Verwendung von
sys.setdefaultencoding()
wurde immer abgeraten , und es ist in py3k ein No-Op geworden. Die Codierung von py3k ist fest mit "utf-8" verbunden, und das Ändern dieser Codierung führt zu einem Fehler.Ich schlage einige Hinweise zum Lesen vor:
quelle
sys.stdout
eineNone
Codierung, z. B. beim Umleiten der Ausgabe eines Python-Programms).sys.setdefaultencoding()
wurde immer entmutigt"UTF-8
.LC_ALL=en_US.UTF-8 python3 -c 'import sys; print(sys.stdout.encoding)'
gibtUTF-8
aberLC_ALL=C python3 -c 'import sys; print(sys.stdout.encoding)'
gibtANSI_X3.4-1968
(oder vielleicht etwas anderes)tl; dr
Die Antwort ist NIE ! (es sei denn, Sie wissen wirklich, was Sie tun)
Das 9/10-fache der Lösung kann mit einem angemessenen Verständnis der Codierung / Decodierung gelöst werden.
1/10 Personen haben ein falsch definiertes Gebietsschema oder eine falsch definierte Umgebung und müssen Folgendes festlegen:
in ihrer Umgebung, um Konsolendruckprobleme zu beheben.
Was tut es?
(durchgestrichen, um eine Wiederverwendung zu vermeiden) Ändert die Standardcodierung / -decodierung, die verwendet wird, wenn Python 2.x einen Unicode () in einen str () konvertieren muss (und umgekehrt) und die Codierung nicht angegeben wird. Dh:sys.setdefaultencoding("utf-8")
In Python 2.x ist die Standardcodierung auf ASCII festgelegt, und die obigen Beispiele schlagen fehl mit:
(Meine Konsole ist als UTF-8 konfiguriert
"€" = '\xe2\x82\xac'
, daher Ausnahme auf\xe2
)oder
wird zulassen, dass diese für mich funktionieren , aber nicht unbedingt für Leute, die UTF-8 nicht verwenden. Die Standardeinstellung von ASCII stellt sicher, dass Annahmen zur Codierung nicht in Code eingebettet werdensys.setdefaultencoding("utf-8")
Konsole
hat auch den Nebeneffektsys.setdefaultencoding("utf-8")
sys.stdout.encoding
, dass es beim Drucken von Zeichen auf die Konsole angezeigt wird. Python verwendet das Gebietsschema des Benutzers (Linux / OS X / Un * x) oder die Codepage (Windows), um dies festzulegen. Gelegentlich ist das Gebietsschema eines Benutzers fehlerhaft und es muss nurPYTHONIOENCODING
die Konsolencodierung korrigiert werden .Beispiel:
Was ist so schlimm an
sys.setdefaultencoding ("utf-8")?Die Leute entwickeln seit 16 Jahren gegen Python 2.x mit dem Verständnis, dass die Standardcodierung ASCII ist.
UnicodeError
Es wurden Ausnahmebehandlungsmethoden geschrieben, um die Konvertierung von Zeichenfolgen in Unicode für Zeichenfolgen zu verarbeiten, die Nicht-ASCII enthalten.Von https://anonbadger.wordpress.com/2015/06/16/why-sys-setdefaultencoding-will-break-code/
Das Ändern einer Konstanten hat dramatische Auswirkungen auf die Module, von denen Sie abhängig sind. Es ist besser, nur die Daten zu korrigieren, die in Ihren Code ein- und ausgehen.
Beispiel Problem
Während die Einstellung der Standardcodierung auf UTF-8 im folgenden Beispiel nicht die Hauptursache ist, zeigt sie, wie Probleme maskiert werden und wie der Code bei Änderungen der Eingabecodierung auf nicht offensichtliche Weise unterbrochen wird: UnicodeDecodeError: 'utf8' Codec kann Byte 0x80 an Position 3131 nicht dekodieren: ungültiges Startbyte
quelle
sys.setdefaultencoding("utf-8")
, aber es ist gut, den Code eher wie Python 3 zu verhalten. Es ist jetzt 2017. Selbst als Sie die Antwort im Jahr 2015 geschrieben haben, war es meiner Meinung nach schon besser, vorwärts als rückwärts zu schauen. Es war tatsächlich die einfachste Lösung für mich, als ich feststellte, dass sich mein Code in Python 2 unterschiedlich verhält, je nachdem, ob die Ausgabe umgeleitet wird (sehr unangenehmes Problem für Python 2). Unnötig zu# coding: utf-8
erwähnen , dass ich dies bereits getan habe und keine Problemumgehungen für Python 3 benötige (ich muss diesetdefaultencoding
Überprüfung der verwendeten Version tatsächlich maskieren ).sys.setdefaultencoding("utf-8")
macht Ihren Py 2.x-Code jedoch nicht mit Python 3 kompatibel. Es werden auch keine externen Module repariert, bei denen davon ausgegangen wird, dass die Standardcodierung ASCII ist. Die Kompatibilität Ihres Codes mit Python 3 ist sehr einfach und erfordert diesen bösen Hack nicht. Zum Beispiel, warum dies sehr reale Probleme verursacht, siehe meine Erfahrung mit Amazon, die mit dieser Annahme herumspieltPYTHONIOENCODING="UTF-8"
half meine Python2.7 Django-1.11-Umgebung. Vielen Dank.detect_encoding
.detect_encoding
ist eine Methode, mit der die Codierung einer Zeichenfolge anhand von Sprachhinweisen erkannt werden kann.Bei Shell funktioniert das Senden an sdtout nicht, das ist also eine Problemumgehung, um an stdout zu schreiben.
Ich habe einen anderen Ansatz gewählt, der nicht ausgeführt wird, wenn sys.stdout.encoding nicht definiert ist oder mit anderen Worten, zuerst PYTHONIOENCODING = UTF-8 exportiert werden muss, um in stdout zu schreiben.
Verwenden Sie also dasselbe Beispiel:
wird funktionieren
quelle
Die erste Gefahr liegt in
reload(sys)
.Wenn Sie ein Modul neu laden, erhalten Sie in Ihrer Laufzeit tatsächlich zwei Kopien des Moduls. Das alte Modul ist wie alles andere ein Python-Objekt und bleibt am Leben, solange Verweise darauf vorhanden sind. Die Hälfte der Objekte zeigt also auf das alte Modul und die Hälfte auf das neue. Wenn Sie Änderungen vornehmen, werden Sie diese nie sehen, wenn ein zufälliges Objekt die Änderung nicht sieht:
Nun
sys.setdefaultencoding()
richtigAlles, was davon betroffen ist, ist die implizite Konvertierung
str<->unicode
.utf-8
Ist nun die vernünftigste Codierung auf dem Planeten (abwärtskompatibel mit ASCII und allen), funktioniert die Konvertierung jetzt "nur", was könnte möglicherweise schief gehen?Nun, alles. Und das ist die Gefahr.
UnicodeError
dass er für Nicht-ASCII-Eingaben ausgegeben wird, oder die Transcodierung mit einem Fehlerhandler, der jetzt ein unerwartetes Ergebnis erzeugt. Und da der gesamte Code mit der Standardeinstellung getestet wird, befinden Sie sich hier ausschließlich auf "nicht unterstütztem" Gebiet , und niemand gibt Ihnen Garantien für das Verhalten des Codes.quelle