it-swarm.com.de

Standardcodierung von Python ändern?

Ich habe viele Probleme mit Python , bei denen ich meine Anwendungen von der Konsole aus ausführen kann. In der IDE EclipsePyDev ist die Standard-Zeichencodierung auf UTF-8 gesetzt, und es geht mir gut.

Ich habe nach der Standardcodierung gesucht und die Leute sagen, dass Python die sys.setdefaultencoding-Funktion beim Start löscht, und wir können sie nicht verwenden.

Also, was ist die beste Lösung dafür?

117
Ali Nadalizadeh

Hier ist eine einfachere Methode (Hack), die Ihnen die setdefaultencoding()-Funktion zurückgibt, die aus sys gelöscht wurde:

import sys
# sys.setdefaultencoding() does not exist, here!
reload(sys)  # Reload does the trick!
sys.setdefaultencoding('UTF8')

Dies ist jedoch keine sichere Sache, dies ist jedoch offensichtlich ein Hack, da sys.setdefaultencoding() beim Starten von Python absichtlich aus sys entfernt wird. Erneutes Aktivieren und Ändern der Standardcodierung kann zum Bruch des Codes führen, der darauf beruht, dass ASCII die Standardeinstellung ist (dieser Code kann von Drittanbietern sein, was die Korrektur im Allgemeinen unmöglich oder gefährlich macht).

134
Eric O Lebigot

Wenn Sie diese Fehlermeldung erhalten, wenn Sie versuchen, die Ausgabe Ihres Skripts umzuleiten

UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-5: ordinal not in range(128)

Exportieren Sie einfach PYTHONIOENCODING in die Konsole und führen Sie dann Ihren Code aus.

export PYTHONIOENCODING=utf8

61
iman

A) Zur Steuerung der sys.getdefaultencoding()-Ausgabe:

python -c 'import sys; print(sys.getdefaultencoding())'

ascii

Dann

echo "import sys; sys.setdefaultencoding('utf-16-be')" > sitecustomize.py

und 

PYTHONPATH=".:$PYTHONPATH" python -c 'import sys; print(sys.getdefaultencoding())'

utf-16-be

Sie könnten sitecustomize.py höher in Ihre PYTHONPATH setzen.

Vielleicht möchten Sie auch reload(sys).setdefaultencoding von @EOL ausprobieren 

B) Um stdin.encoding und stdout.encoding zu steuern, die Sie PYTHONIOENCODING einstellen möchten:

python -c 'import sys; print(sys.stdin.encoding, sys.stdout.encoding)'

ascii ascii

Dann 

PYTHONIOENCODING="utf-16-be" python -c 'import sys; 
print(sys.stdin.encoding, sys.stdout.encoding)'

utf-16-be utf-16-be

Schließlich: können Sie A) oder B) oder beide verwenden!

46
lukmdo

Beginnend mit PyDev 3.4.1 wird die Standardcodierung nicht mehr geändert. Siehe dieses Ticket für Details.

Bei früheren Versionen besteht die Lösung darin, sicherzustellen, dass PyDev nicht mit UTF-8 als Standardcodierung ausgeführt wird. Führen Sie unter Eclipse Dialogeinstellungen aus ("Laufkonfigurationen", wenn ich mich recht erinnere); Sie können die Standardkodierung auf der Registerkarte "Allgemein" auswählen. Ändern Sie den Code in US-ASCII, wenn Sie diese Fehler "zu früh" haben möchten (in Ihrer PyDev-Umgebung). Siehe auch einen ursprünglichen Blogeintrag für diese Problemumgehung .

17
ChristopheD

In Bezug auf Python2 (und nur Python2) sind einige der vorherigen Antworten auf den folgenden Hack angewiesen:

import sys
reload(sys)  # Reload is a hack
sys.setdefaultencoding('UTF8')

Es wird davon abgeraten, es zu benutzen (check this oder this )

In meinem Fall kommt es zu einem Nebeneffekt: Ich verwende ipython-Notebooks, und sobald ich den Code ausgeführt habe, funktioniert die "Drucken" -Funktion nicht mehr. Ich denke, dass es eine Lösung dafür geben würde, aber trotzdem denke ich, dass der Hack nicht die richtige Option sein sollte.

Nachdem ich viele Optionen ausprobiert hatte, funktionierte für mich mit demselben Code im sitecustomize.py, wobei dieser Code als bezeichnet werden soll. Nach der Bewertung dieses Moduls wird die Funktion setdefaultencoding aus sys entfernt.

Die Lösung ist also, an die Datei /usr/lib/python2.7/sitecustomize.py den Code anzuhängen:

import sys
sys.setdefaultencoding('UTF8')

Wenn ich virtualenvwrapper verwende, ist die Datei, die ich bearbeite, ~/.virtualenvs/venv-name/lib/python2.7/sitecustomize.py.

Und wenn ich mit Python-Notebooks und Conda verwende, ist es ~/anaconda2/lib/python2.7/sitecustomize.py

12
kiril

Es gibt einen aufschlussreichen Blogbeitrag darüber.

Siehe https://anonbadger.wordpress.com/2015/06/16/why-sys-setdefaultencoding-will-break-code/ .

Ich umschreibe den Inhalt unten.

In Python 2, das hinsichtlich der Codierung von Strings nicht so stark typisiert war, konnten Sie Operationen mit unterschiedlich codierten Strings ausführen und erfolgreich sein. Z.B. Folgendes würde True zurückgeben.

u'Toshio' == 'Toshio'

Dies würde für jede (normale, nicht fixierte) Zeichenfolge gelten, die in sys.getdefaultencoding() codiert wurde, die standardmäßig ascii war, nicht jedoch andere.

Die Standardcodierung sollte systemweit in site.py geändert werden, jedoch nicht an anderer Stelle. Die Hacks (auch hier dargestellt), um es in Benutzermodule zu setzen, waren genau das: Hacks, nicht die Lösung.

Python 3 hat die Systemcodierung in utf-8 geändert (wenn LC_CTYPE Unicode-fähig ist). Das grundlegende Problem wurde jedoch mit der Anforderung gelöst, Byte-Zeichenfolgen explizit zu codieren, wenn sie mit Unicode-Zeichenfolgen verwendet werden.

7
ibotty

Erstens: reload(sys) und das Festlegen einer zufälligen Standardcodierung, die nur die Notwendigkeit eines Ausgabeterminals betrifft, ist schlechte Praxis. reload ändert oft Dinge in sys, die abhängig von der Umgebung eingerichtet wurden - z. sys.stdin/stdout-Streams, sys.excepthook usw. 

Löse das Kodierungsproblem bei stdout

Die beste Lösung, die ich kenne, um das Kodierungsproblem von print 'Unicode-Strings und jenseits von Ascii strs (z. B. von Literalen) auf sys.stdout zu lösen, ist: sich um ein sys.stdout (dateiähnliches Objekt) zu kümmern, das fähig ist optional tolerant bezüglich der Bedürfnisse:

  • Wenn sys.stdout.encoding aus irgendeinem Grund None ist oder nicht existiert oder fälschlicherweise falsch oder "kleiner" ist als das, was das stdout-Terminal oder der Stream tatsächlich kann, dann versuchen Sie, ein korrektes .encoding-Attribut anzugeben. Zuletzt, indem Sie sys.stdout & sys.stderr durch ein dateiähnliches Objekt ersetzen.

  • Wenn das Terminal/Stream immer noch nicht alle vorkommenden Unicode-Zeichen codieren kann und Sie print_ nicht einfach deshalb brechen möchten, können Sie im umwandlungsdateiähnlichen Objekt ein encode-with-replace-Verhalten 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 __== '__main__':
    if sys.stdout.isatty():
        sys.stdout = sys.stderr = SmartStdout()

    us = u'aouäöüфżß²'
    print us
    sys.stdout.flush()

Verwenden der normalen String-Literale in Python 2/2 + 3-Code

Der einzige gute Grund, die globale Standardcodierung (nur auf UTF-8) zu ändern, ist meiner Meinung nach eine Anwendung Quellcode Entscheidung - und nicht aufgrund von I/O-Stream-Codierungsproblemen: Zum Schreiben von Zeichenkettenliteralen außerhalb von ASCII-Zeichen Code, ohne dazu gezwungen zu sein, immer den Unicode-Escape-Code im u'string'-Stil zu verwenden. Dies kann ziemlich konsistent gemacht werden (trotz der Äußerungen von anonbadger), indem auf eine Python 2- oder Python 2 + 3-Quellcodebasis geachtet wird, die ascii oder UTF-8-Stringliter konsequent verwendet - bis zu diesen Zeichenfolgen werden möglicherweise einer stillen Unicode-Konvertierung unterzogen und wechseln zwischen Modulen oder werden möglicherweise zu stdout. Bevorzugen Sie "# encoding: utf-8" oder ASCII (keine Deklaration). Ändern oder löschen Sie Bibliotheken, die nach wie vor auf sehr dumme Weise tödlich auf die Standardcodierungsfehler von ASCII-Dateien über chr # 127 hinausgehen (was heutzutage selten ist).

Und machen Sie das beim Start der Anwendung (und/oder über sitecustomize.py) zusätzlich zum oben genannten SmartStdout-Schema - ohne 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 __== '__main__':
    sys.stdout = sys.stderr = SmartStdout()
    set_defaultencoding_globally('utf-8') 
    s = 'aouäöüфżß²'
    print s

Auf diese Weise arbeiten String-Literale und die meisten Operationen (außer der Zeichen-Iteration) auf komfortable Weise, ohne an Unicode-Konvertierung zu denken, als ob es nur Python3 gäbe. Datei-I/O-Vorgänge erfordern natürlich immer besondere Sorgfalt bei der Kodierung - wie in Python3.

Hinweis: Plains-Zeichenfolgen werden dann implizit von utf-8 in SmartStdout in Unicode konvertiert, bevor sie in den Ausgabestrom konvertiert werden.

2
kxr

Dies hat das Problem für mich behoben.

import os
os.environ["PYTHONIOENCODING"] = "utf-8"
2
twasbrillig

Dies ist ein schneller Hack für alle, die (1) auf einer Windows-Plattform (2) mit Python 2.7 und (3) laufen, weil ein Nizza-Teil der Software (dh, nicht von Ihnen geschrieben, also nicht sofort ein Kandidat für das Kodieren/Dekodieren ist) Manöver) werden die "hübschen Unicode-Zeichen" in der IDLE-Umgebung nicht anzeigen (Pythonwin druckt Unicode-Fine-Code). Beispielsweise die ordentlichen First Order Logic-Symbole, die Stephan Boyer in der Ausgabe seines pädagogischen Beweisers bei First Order Logic) verwendet Prover .

Mir gefiel die Idee, ein sys-reload zu erzwingen, nicht und ich konnte das System nicht dazu bringen, mit Umgebungsvariablen wie PYTHONIOENCODING zusammenzuarbeiten (versuchte direkte Windows-Umgebungsvariable und löschte dies auch in sitecustomize.py in site-packages als eine Liner = 'utf-8').

Wenn Sie bereit sind, Ihren Weg zum Erfolg zu hacken, wechseln Sie zu Ihrem IDLE-Verzeichnis. In der Regel: "C:\Python27\Lib\idlelib" Suchen Sie die Datei IOBinding.py. Erstellen Sie eine Kopie dieser Datei und speichern Sie sie an einem anderen Ort, damit Sie bei Bedarf wieder zum ursprünglichen Verhalten zurückkehren können. Öffnen Sie die Datei in der Idlelib mit einem Editor (z. B. IDLE). Gehen Sie zu diesem Codebereich:

# Encoding for file names
filesystemencoding = sys.getfilesystemencoding()

encoding = "ascii"
if sys.platform == 'win32':
    # On Windows, we could use "mbcs". However, to give the user
    # a portable encoding name, we need to find the code page 
    try:
        # --> 6/5/17 hack to force IDLE to display utf-8 rather than cp1252
        # --> encoding = locale.getdefaultlocale()[1]
        encoding = 'utf-8'
        codecs.lookup(encoding)
    except LookupError:
        pass

Mit anderen Worten, kommentieren Sie die ursprüngliche Codezeile nach 'try' aus, wodurch die Kodierungsvariable locale.getdefaultlocale entspricht (da dies cp1252 ergibt, das Sie nicht möchten) und stattdessen brute zwingt es zu 'utf-8' (durch Hinzufügen der Zeile 'coding =' utf-8 'wie gezeigt). 

Ich glaube, dass dies nur die IDLE-Anzeige für stdout betrifft und nicht die Kodierung, die für Dateinamen usw. verwendet wird (die in der Dateisystemkodierung vor erhalten wird). Wenn Sie mit einem anderen Code, den Sie später in IDLE ausführen, ein Problem haben, ersetzen Sie einfach die Datei IOBinding.py durch die ursprüngliche, nicht geänderte Datei.

0
Dalton Bentley

Hier ist der Ansatz, mit dem ich Code produzierte, der sowohl mit python2 als auch python3 kompatibel war und immer die Ausgabe von utf8 hervorbrachte. Ich habe diese Antwort anderswo gefunden, kann mich aber nicht an die Quelle erinnern.

Dieser Ansatz funktioniert durch Ersetzen von sys.stdout durch etwas, das ist nicht ziemlich dateiartig (aber es werden nur Elemente in der Standardbibliothek verwendet). Dies kann durchaus zu Problemen für die zugrunde liegenden Bibliotheken führen. In einem einfachen Fall, in dem Sie die Verwendung von sys.stdout durch Ihr Framework gut kontrollieren können, kann dies ein vernünftiger Ansatz sein.

sys.stdout = io.open(sys.stdout.fileno(), 'w', encoding='utf8')
0
Att Righ