Wenn die Ausgabe eines Python - Programms weitergeleitet wird, ist der Python - Interpreter hinsichtlich der Codierung verwirrt und setzt ihn auf None. Dies bedeutet ein Programm wie dieses:
# -*- coding: utf-8 -*-
print u"åäö"
wird gut funktionieren, wenn normal ausgeführt, aber scheitern mit:
UnicodeEncodeError: Der Codec 'ascii' kann das Zeichen u '\ xa0' an Position 0 nicht codieren: Ordnungszahl nicht im Bereich (128)
bei Verwendung in einer Rohrsequenz.
Was ist der beste Weg, um diese Funktion beim Leiten zu erreichen? Kann ich ihm einfach sagen, welche Codierung das Shell/Dateisystem/was auch immer verwendet?
Die Vorschläge, die ich bisher gesehen habe, sind, Ihre site.py direkt zu ändern oder die defaultencoding mit diesem Hack fest zu codieren:
# -*- coding: utf-8 -*-
import sys
reload(sys)
sys.setdefaultencoding('utf-8')
print u"åäö"
Gibt es einen besseren Weg, um Rohrleitungen zum Laufen zu bringen?
Ihr Code funktioniert, wenn er in einem Skript ausgeführt wird, da Python codiert die Ausgabe in die von Ihrer Terminalanwendung verwendete Codierung. Wenn Sie Pipes ausführen, müssen Sie sie selbst codieren.
Als Faustregel gilt: Verwenden Sie Unicode immer intern. Dekodieren Sie, was Sie empfangen, und kodieren Sie, was Sie senden.
# -*- coding: utf-8 -*-
print u"åäö".encode('utf-8')
Ein weiteres didaktisches Beispiel ist ein Python) - Programm, das zwischen ISO-8859-1 und UTF-8 konvertiert und alles dazwischen in Großbuchstaben schreibt.
import sys
for line in sys.stdin:
# Decode what you receive:
line = line.decode('iso8859-1')
# Work with Unicode internally:
line = line.upper()
# Encode what you send:
line = line.encode('utf-8')
sys.stdout.write(line)
Das Festlegen der Systemstandardcodierung ist eine schlechte Idee, da sich einige Module und Bibliotheken, die Sie verwenden, darauf verlassen können, dass es sich um ASCII handelt. Tu es nicht.
Zunächst zu dieser Lösung:
# -*- coding: utf-8 -*-
print u"åäö".encode('utf-8')
Es ist nicht praktisch, jedes Mal explizit mit einer bestimmten Codierung zu drucken. Das wäre repetitiv und fehleranfällig.
Eine bessere Lösung ist, zu Beginn Ihres Programms sys.stdout
zu ändern, um mit einer ausgewählten Codierung zu codieren. Hier ist eine Lösung, die ich auf Python: Wie wird sys.stdout.encoding ausgewählt? , insbesondere ein Kommentar von "toka":
import sys
import codecs
sys.stdout = codecs.getwriter('utf8')(sys.stdout)
Möglicherweise möchten Sie versuchen, die Umgebungsvariable "PYTHONIOENCODING" in "utf_8" zu ändern. Ich habe eine Seite über meine Tortur mit diesem Problem geschrieben .
Tl; dr des Blogposts:
import sys, locale, os
print(sys.stdout.encoding)
print(sys.stdout.isatty())
print(locale.getpreferredencoding())
print(sys.getfilesystemencoding())
print(os.environ["PYTHONIOENCODING"])
print(chr(246), chr(9786), chr(9787))
gibt Ihnen
utf_8
False
ANSI_X3.4-1968
ascii
utf_8
ö ☺ ☻
export PYTHONIOENCODING=utf-8
erledige den Job, kann ihn aber nicht auf python selbst setzen ...
was wir tun können, ist zu überprüfen, ob keine Einstellung vorhanden ist, und den Benutzer anzuweisen, diese Einstellung vorzunehmen, bevor das Skript aufgerufen wird:
if __== '__main__':
if (sys.stdout.encoding is None):
print >> sys.stderr, "please set python env PYTHONIOENCODING=UTF-8, example: export PYTHONIOENCODING=UTF-8, when write to stdout."
exit(1)
Aktualisieren Sie, um auf den Kommentar zu antworten: Das Problem tritt nur bei der Weiterleitung an stdout auf. Ich habe in Fedora 25 Python 2.7.13 getestet
python --version
Python 2.7.13
katze b.py
#!/usr/bin/env python
#-*- coding: utf-8 -*-
import sys
print sys.stdout.encoding
laufen ./b.py
UTF-8
laufen ./b.py | geringer, weniger
None
Ich hatte ein ähnliches Problem letzte Woche . Es war einfach, in meinem IDE (PyCharm) zu beheben.
Hier war meine Lösung:
Ausgehend von der PyCharm-Menüleiste: Datei -> Einstellungen ... -> Editor -> Dateicodierungen, stellen Sie dann "IDE-Codierung", "Projektcodierung" und "Standardcodierung für Eigenschaftendateien" auf ALLES in UTF-8 ein und sie funktioniert jetzt wie ein Zauber.
Hoffe das hilft!
Eine wohl bereinigte Version von Craig McQueens Antwort.
import sys, codecs
class EncodedOut:
def __init__(self, enc):
self.enc = enc
self.stdout = sys.stdout
def __enter__(self):
if sys.stdout.encoding is None:
w = codecs.getwriter(self.enc)
sys.stdout = w(sys.stdout)
def __exit__(self, exc_ty, exc_val, tb):
sys.stdout = self.stdout
Verwendungszweck:
with EncodedOut('utf-8'):
print u'ÅÄÖåäö'
Ich könnte es mit einem Aufruf an "automatisieren":
def __fix_io_encoding(last_resort_default='UTF-8'):
import sys
if [x for x in (sys.stdin,sys.stdout,sys.stderr) if x.encoding is None] :
import os
defEnc = None
if defEnc is None :
try:
import locale
defEnc = locale.getpreferredencoding()
except: pass
if defEnc is None :
try: defEnc = sys.getfilesystemencoding()
except: pass
if defEnc is None :
try: defEnc = sys.stdin.encoding
except: pass
if defEnc is None :
defEnc = last_resort_default
os.environ['PYTHONIOENCODING'] = os.environ.get("PYTHONIOENCODING",defEnc)
os.execvpe(sys.argv[0],sys.argv,os.environ)
__fix_io_encoding() ; del __fix_io_encoding
Ja, es ist möglich, hier eine Endlosschleife zu erhalten, wenn dieses "setenv" fehlschlägt.
Ich bin in einer älteren Anwendung auf dieses Problem gestoßen, und es war schwierig zu identifizieren, wo was gedruckt wurde. Ich habe mir bei diesem Hack geholfen:
# encoding_utf8.py
import codecs
import builtins
def print_utf8(text, **kwargs):
print(str(text).encode('utf-8'), **kwargs)
def print_utf8(fn):
def print_fn(*args, **kwargs):
return fn(str(*args).encode('utf-8'), **kwargs)
return print_fn
builtins.print = print_utf8(print)
Oben auf meinem Skript test.py:
import encoding_utf8
string = 'Axwell Λ Ingrosso'
print(string)
Beachten Sie, dass dadurch ALLE zu druckenden Aufrufe geändert werden, um eine Codierung zu verwenden, sodass Ihre Konsole Folgendes ausgibt:
$ python test.py
b'Axwell \xce\x9b Ingrosso'
Ich dachte nur, ich würde hier etwas erwähnen, mit dem ich lange experimentieren musste, bevor ich endlich realisierte, was los war. Dies mag für alle hier so offensichtlich sein, dass sie sich nicht die Mühe gemacht haben, es zu erwähnen. Aber es hätte mir geholfen, wenn sie es getan hätten, also nach diesem Prinzip ...!
NB: Ich verwende speziell Jython , Version 2.7, daher trifft dies möglicherweise nicht auf CPython zu.
NB2: Die ersten beiden Zeilen meiner .py-Datei sind:
# -*- coding: utf-8 -*-
from __future__ import print_function
Der String-Konstruktionsmechanismus "%" (AKA "Interpolationsoperator") verursacht auch ZUSÄTZLICHE Probleme ... Wenn die Standardcodierung der "Umgebung" ASCII ist und Sie versuchen, so etwas zu tun
print( "bonjour, %s" % "fréd" ) # Call this "print A"
Sie werden in Eclipse keine Schwierigkeiten haben ... In einer Windows-CLI (DOS-Fenster) werden Sie feststellen, dass die Codierung Codepage 85 (mein Windows 7-Betriebssystem) oder etwas Ähnliches ist, das mit Europa zurechtkommt zumindest Zeichen mit Akzent, damit es funktioniert.
print( u"bonjour, %s" % "fréd" ) # Call this "print B"
wird auch funktionieren.
Wenn Sie OTOH über die CLI zu einer Datei weiterleiten, lautet die Standardcodierung None (Keine). Die Standardeinstellung lautet ASCII (auf meinem Betriebssystem ohnehin). Keiner der oben genannten Ausdrucke kann verarbeitet werden. (gefürchteter Codierungsfehler).
Dann könnten Sie daran denken, Ihre Standardausgabe mit umzuleiten
sys.stdout = codecs.getwriter('utf8')(sys.stdout)
und versuchen Sie, die CLI-Piping-Funktion für eine Datei auszuführen ... Seltsamerweise funktioniert Druck A oben ... Druck B oben löst jedoch den Codierungsfehler aus! Folgendes wird jedoch funktionieren:
print( u"bonjour, " + "fréd" ) # Call this "print C"
Die Schlussfolgerung, zu der ich gekommen bin (vorläufig), ist, dass, wenn eine Zeichenfolge, die als nicode - Zeichenfolge mit dem Präfix "u" angegeben ist, an den% -Handhabungsmechanismus übergeben wird, dies anscheinend die Verwendung von beinhaltet die Standard-Umgebungskodierung , unabhängig davon, ob Sie stdout auf Weiterleitung eingestellt haben!
Wie die Leute damit umgehen, ist eine Frage der Wahl. Ich würde einen Unicode-Experten begrüßen, der erklärt, warum dies passiert, ob ich es auf irgendeine Weise falsch verstanden habe, was die bevorzugte Lösung dafür ist, ob es auch für CPython gilt, ob es in Python 3 usw. usw.
Unter Ubuntu 12.10 und GNOME Terminal wird kein Fehler erzeugt, wenn das Programm auf stdout druckt oder eine Pipe für andere Programme verwendet. Sowohl die Dateicodierung als auch die Terminalcodierung ist TF-8 .
$ cat a.py
# -*- coding: utf-8 -*-
print "åäö"
$ python a.py
åäö
$ python a.py | tee out
åäö
Welches Betriebssystem und welchen Terminalemulator verwenden Sie? Ich habe gehört, dass einige meiner Kollegen ähnliche Probleme haben, wenn sie iTerm 2 und OS X verwenden. iTerm 2 kann der Schuldige sein.
Update: Diese Antwort ist falsch - siehe Kommentare für Details