Wenn ich Sysadmin-Skripte in Python schreibe, ist der Puffer auf sys.stdout, die jeden Aufruf von print() wirkt nervend, weil ich nicht Ich möchte nicht warten, bis ein Puffer geleert wird, und dann einen großen Teil der Zeilen gleichzeitig auf dem Bildschirm anzeigen. Stattdessen möchte ich einzelne Zeilen ausgeben, sobald eine neue Ausgabe vom Skript generiert wird. Ich möchte nicht einmal auf Zeilenumbrüche warten, um die Ausgabe zu sehen.Python-Standard-Idiom zum Setzen von sys.stdout Puffer auf Null funktioniert nicht mit Unicode
Ein oft Idiom verwendet, um dieses in Python zu tun ist,
import os
import sys
sys.stdout = os.fdopen(sys.stdout.fileno(), 'wb', 0)
Das ist für mich für eine lange Zeit gut funktioniert. Jetzt ist mir aufgefallen, dass es mit Unicode nicht funktioniert. Bitte sehen Sie das folgende Skript:
#!/usr/bin/python
# -*- coding: utf-8 -*-
from __future__ import print_function, unicode_literals
import os
import sys
print('Original encoding: {}'.format(sys.stdout.encoding))
sys.stdout = os.fdopen(sys.stdout.fileno(), 'wb', 0)
print('New encoding: {}'.format(sys.stdout.encoding))
text = b'Eisb\xe4r'
print(type(text))
print(text)
text = text.decode('latin-1')
print(type(text))
print(text)
Dies ist auf die folgende Ausgabe führt:
Original encoding: UTF-8
New encoding: None
<type 'str'>
Eisb▒r
<type 'unicode'>
Traceback (most recent call last):
File "./export_debug.py", line 18, in <module>
print(text)
UnicodeEncodeError: 'ascii' codec can't encode character u'\xe4' in position 4: ordinal not in range(128)
Es mir Stunden in Anspruch nahm den Grund dafür aufzuspüren (meine Original-Skript war viel länger als dieser minimale Debug-Skript). Es ist die Linie
sys.stdout = os.fdopen(sys.stdout.fileno(), 'wb', 0)
, die ich seit Jahren so kein Problem mit ihm erwartete. Kommentieren Sie einfach diese Zeile und die korrekte Ausgabe sollte wie folgt aussehen:
Original encoding: UTF-8
New encoding: UTF-8
<type 'str'>
Eisb▒r
<type 'unicode'>
Eisbär
Also was ist das Skript zu tun? Zur Vorbereitung meines Python 2.7-Code so nahe wie möglich zu Python 3.x, ich bin immer mit
from __future__ import print_function, unicode_literals
dem Python den neuen Druck verwenden macht() - Funktion aber noch wichtiger: es Python Speicher macht alle Strings als Unicode intern standardmäßig. Ich habe eine Menge von Latin-1/ISO-8859-1 codierten Daten, zum Beispiel
text = b'Eisb\xe4r'
damit die beabsichtigte Art und Weise zu umgehen, muß ich es zuerst in Unicode entschlüsseln, das ist, was
text = text.decode('latin-1')
ist für. Da die Standardcodierung auf meinem System UTF-8 ist, verschlüsselt Python die interne Unicode-Zeichenkette immer dann, wenn ich einen String drucke, in UTF-8. Aber zuerst muss es intern in perfektem Unicode sein.
Nun, das alles funktioniert im Allgemeinen gut, nur nicht mit einem Null-Byte-Ausgangspuffer so weit. Irgendwelche Ideen? Ich habe bemerkt, dass sys.stdout.encoding nach der Null-Pufferungszeile nicht gesetzt ist, aber ich weiß nicht, wie ich es wieder einstellen soll. Es ist ein schreibgeschütztes Attribut und die OS-Umgebungsvariablen LC_ALL oder LC_CTYPE scheinen nur am Anfang des Python-Interpreters ausgewertet zu werden.
Bt .: Eisbär ist das deutsche Wort für Eisbär.
@martineau Nun funktioniert der Vorschlag sys.stdout = codecs.getwriter ('utf8') (sys.stdout) auch nicht. Ich habe wirklich viel versucht und gesucht. Ich denke also, dass Ideen, ohne sie zu testen, nicht viel helfen. –
Ich habe die Frage für Sie migriert. Das nächste Mal, einfach "Flagge" für die Aufmerksamkeit des Moderators und sagen Sie uns, was Sie brauchen! :) – slhck
@MartenLehmann: Die Tatsache, dass es nicht getestet wurde, ist, warum ich es als Kommentar eher eine Antwort postete. – martineau