Primo: reload(sys)
impostare una codifica predefinita casuale solo per quanto riguarda la necessità di un flusso di terminali di output è una cattiva pratica. reload
cambia spesso le cose in sys che sono state messe in atto in base all'ambiente - ad esempio flussi sys.stdin / stdout, sys.excepthook, ecc.
Risolvere il problema di codifica su stdout
La migliore soluzione che conosco per risolvere il problema di codifica di print
'ing stringhe unicode e oltre-ascii str
' (es. Letterali) su sys.stdout è: prendersi cura di un sys.stdout (oggetto simile a un file) che è capace e facoltativamente tollerante rispetto alle esigenze:
Quando sys.stdout.encoding
è None
per qualche motivo, o inesistente, o erroneamente falso o "meno" di quello di cui è realmente capace il terminale stdout o lo stream, allora prova a fornire un .encoding
attributo corretto . Finalmente sostituendo sys.stdout & sys.stderr
con un oggetto simile a file di traduzione.
Quando il terminale / flusso non è ancora in grado di codificare tutti i caratteri Unicode che si verificano e quando non si desidera interrompere print
solo per questo motivo, è possibile introdurre un comportamento di codifica con sostituzione nell'oggetto simile a file di traduzione.
Ecco un esempio:
#!/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()
Utilizzo dei valori letterali stringa stringa beyond-ascii nel codice Python 2/2 + 3
L'unico buon motivo per cambiare la codifica globale predefinita (solo su UTF-8) penso sia riguardo a una decisione sul codice sorgente dell'applicazione - e non a causa di problemi di codifica del flusso I / O: per scrivere valori letterali stringa oltre-ascii nel codice senza essere forzati per usare sempre lo u'string'
stile Unicode Escaping. Questo può essere fatto in modo piuttosto coerente (nonostante quanto dice l'articolo di Anonbadger ) prendendosi cura di una base di codice sorgente Python 2 o Python 2 + 3 che usa coerentemente letterali di stringhe ASCII o UTF-8 coerentemente, per quanto quelle stringhe potenzialmente subiscano silenziose conversione unicode e spostamento tra i moduli o potenzialmente passaggio a stdout. Per questo, preferisci "# encoding: utf-8
"o ascii (nessuna dichiarazione). Cambia o elimina le librerie che si basano ancora fatalmente sugli errori di codifica ascii di default oltre chr # 127 (che è raro oggi).
E fai così all'avvio dell'applicazione (e / o tramite sitecustomize.py) oltre allo SmartStdout
schema sopra - senza usare 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
In questo modo i letterali di stringa e la maggior parte delle operazioni (tranne l'iterazione dei caratteri) funzionano in modo confortevole senza pensare alla conversione unicode come se ci fosse solo Python3. Naturalmente, l'I / O dei file richiede sempre particolare attenzione per quanto riguarda le codifiche, come in Python3.
Nota: le stringhe di pianura vengono quindi convertite implicitamente da utf-8 in unicode SmartStdout
prima di essere convertite nel flusso di output che lo circonda.