Po pierwsze: reload(sys)a ustawienie jakiegoś losowego domyślnego kodowania tylko ze względu na potrzebę strumienia terminala wyjściowego jest złą praktyką. reloadczęsto zmienia rzeczy w sys, które zostały wprowadzone w zależności od środowiska - np. strumienie sys.stdin / stdout, sys.excepthook itp.
Rozwiązanie problemu z kodowaniem na stdout
Najlepszym rozwiązaniem, jakie znam, aby rozwiązać problem z kodowaniem w przypadku printciągów znaków Unicode i poza-ascii str(np. Z literałów) na sys.stdout jest: zająć się sys.stdout (obiekt podobny do pliku), który jest zdolny i opcjonalnie tolerancyjny w stosunku do potrzeb:
Kiedy sys.stdout.encodingjest Nonez jakiegoś powodu lub nie istnieje, błędnie fałszywe lub „mniejsze” niż to, do czego naprawdę jest zdolny terminal lub strumień standardowego strumienia, spróbuj podać poprawny .encodingatrybut. W końcu zastępując sys.stdout & sys.stderrgo tłumaczącym obiektem podobnym do pliku.
Kiedy terminal / strumień nadal nie może zakodować wszystkich występujących znaków Unicode i nie chcesz z tego powodu łamać znaków, printmożesz wprowadzić zachowanie kodowania ze zamianą w tłumaczącym obiekcie podobnym do pliku.
Oto przykład:
#!/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()
Używanie zwykłych literałów łańcuchowych poza ascii w kodzie Python 2/2 + 3
Myślę, że jedynym dobrym powodem zmiany globalnego domyślnego kodowania (tylko na UTF-8) jest decyzja dotycząca kodu źródłowego aplikacji - a nie problemy z kodowaniem strumienia I / O: Do zapisywania literałów łańcuchowych poza ascii do kodu bez wymuszania aby zawsze używać u'string'ucieczki stylu Unicode. Można to zrobić dość konsekwentnie (pomimo tego, co mówi artykuł anonbadger ), dbając o podstawę kodu źródłowego Python 2 lub Python 2 + 3, który konsekwentnie używa zwykłych literałów ciągów ascii lub UTF-8 - o ile te ciągi potencjalnie podlegają wyciszeniu Konwersja Unicode i przechodzenie między modułami lub potencjalnie przejście do standardowego wyjścia. W tym celu preferuj „# encoding: utf-8"lub ascii (brak deklaracji). Zmień lub usuń biblioteki, które nadal polegają w bardzo głupi sposób na błędach domyślnego kodowania ascii poza chr # 127 (co jest dziś rzadkością).
I zrób to na starcie aplikacji (i / lub przez sitecustomize.py) jako dodatek do SmartStdoutpowyższego schematu - bez użycia 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
W ten sposób literały łańcuchowe i większość operacji (z wyjątkiem iteracji znaków) działają wygodnie, bez myślenia o konwersji Unicode, tak jakby istniał tylko Python3. Oczywiście we / wy pliku zawsze trzeba uważać na kodowanie - tak jak w Pythonie3.
Uwaga: łańcuchy SmartStdoutzwykłe są następnie niejawnie konwertowane z utf-8 do Unicode, zanim zostaną przekonwertowane na kodowanie strumienia wyjściowego.