Erstens: Das reload(sys)
Festlegen einer zufälligen Standardcodierung nur in Bezug auf die Notwendigkeit eines Ausgabe-Terminal-Streams ist eine schlechte Praxis. reload
ändert häufig Dinge in sys, die je nach Umgebung eingerichtet wurden - z. B. sys.stdin / stdout-Streams, sys.excepthook usw.
Lösen des Codierungsproblems auf stdout
Die beste Lösung, die ich kenne, um das Codierungsproblem zu lösen print
, Unicode-Strings und str
Beyond-ASCIIs (z. B. aus Literalen) auf sys.stdout zu lösen, ist: sich um ein sys.stdout (dateiähnliches Objekt) zu kümmern, das fähig ist und optional tolerant in Bezug auf die Bedürfnisse:
Wenn sys.stdout.encoding
es None
aus irgendeinem Grund oder nicht vorhanden oder fälschlicherweise falsch oder "weniger" ist als das, wozu das Standardterminal oder der Standard-Stream wirklich in der Lage ist, versuchen Sie, ein korrektes .encoding
Attribut bereitzustellen . Zuletzt durch Ersetzen sys.stdout & sys.stderr
durch ein übersetzendes dateiähnliches Objekt.
Wenn das Terminal / der Stream immer noch nicht alle vorkommenden Unicode-Zeichen codieren kann und Sie diese nicht print
nur aus diesem Grund unterbrechen möchten , können Sie ein Verhalten zum Codieren mit Ersetzen in das übersetzungsdateiähnliche Objekt einführen.
Hier ein Beispiel:
#!/usr/bin/env python
# encoding: utf-8
import sys
class SmartStdout:
def __init__(self, encoding=None, org_stdout=None):
if org_stdout is None:
org_stdout = getattr(sys.stdout, 'org_stdout', sys.stdout)
self.org_stdout = org_stdout
self.encoding = encoding or \
getattr(org_stdout, 'encoding', None) or 'utf-8'
def write(self, s):
self.org_stdout.write(s.encode(self.encoding, 'backslashreplace'))
def __getattr__(self, name):
return getattr(self.org_stdout, name)
if __name__ == '__main__':
if sys.stdout.isatty():
sys.stdout = sys.stderr = SmartStdout()
us = u'aouäöüфżß²'
print us
sys.stdout.flush()
Verwenden von einfachen String-Literalen jenseits von ASCII in Python 2/2 + 3-Code
Der einzige gute Grund, die globale Standardcodierung (nur auf UTF-8) zu ändern, betrifft meiner Meinung nach eine Entscheidung über den Quellcode der Anwendung - und nicht aufgrund von Problemen mit der Codierung von E / A-Streams: Zum Schreiben von String-Literalen über ASCII hinaus in Code, ohne dazu gezwungen zu werden um immer u'string'
Style-Unicode-Escape zu verwenden. Dies kann ziemlich konsistent erfolgen (trotz des Artikels von anonbadger ), indem eine Python 2- oder Python 2 + 3-Quellcodebasis verwendet wird, die konsistente ASCII- oder UTF-8-Zeichenfolgenliterale konsistent verwendet - sofern diese Zeichenfolgen möglicherweise stumm geschaltet werden Unicode-Konvertierung und zwischen Modulen wechseln oder möglicherweise zu stdout wechseln. Dafür lieber "# encoding: utf-8
"oder ascii (keine Deklaration). Ändern oder Löschen von Bibliotheken, die sich immer noch auf sehr dumme Weise auf ASCII-Standardcodierungsfehler jenseits von chr # 127 stützen (was heute selten ist).
Und tun Sie dies beim Start der Anwendung (und / oder über sitecustomize.py) zusätzlich zu dem SmartStdout
oben beschriebenen Schema - ohne Folgendes zu verwenden reload(sys)
:
...
def set_defaultencoding_globally(encoding='utf-8'):
assert sys.getdefaultencoding() in ('ascii', 'mbcs', encoding)
import imp
_sys_org = imp.load_dynamic('_sys_org', 'sys')
_sys_org.setdefaultencoding(encoding)
if __name__ == '__main__':
sys.stdout = sys.stderr = SmartStdout()
set_defaultencoding_globally('utf-8')
s = 'aouäöüфżß²'
print s
Auf diese Weise funktionieren String-Literale und die meisten Operationen (mit Ausnahme der Zeicheniteration) komfortabel, ohne über die Unicode-Konvertierung nachzudenken, als gäbe es nur Python3. Datei-E / A benötigen natürlich immer besondere Sorgfalt bei der Codierung - wie in Python3.
Hinweis: Einfache Zeichenfolgen werden dann implizit von utf-8 in Unicode in SmartStdout
konvertiert, bevor sie in den folgenden Ausgabestream konvertiert werden.