Во-первых: reload(sys)
и установка некоторой случайной кодировки по умолчанию только с учетом потребности в потоке выходного терминала - плохая практика. reload
часто меняет вещи в sys, которые были введены в действие в зависимости от среды, например потоки sys.stdin / stdout, sys.excepthook и т. д.
Решение проблемы с кодированием на stdout
Лучшее решение, которое я знаю для решения проблемы кодирования print
строк unicode и за пределами ascii str
(например, из литералов) в sys.stdout, это: позаботиться о sys.stdout (файловом объекте), который способен и необязательно толерантный в отношении потребностей:
Когда sys.stdout.encoding
это None
по какой - то причине, или несуществующего, или ошибочно ложной или «меньше» , чем стандартный вывод терминала или поток действительно способен, а затем попытаться обеспечить правильный .encoding
атрибут. Наконец, путем замены sys.stdout & sys.stderr
на переводящий файловый объект.
Когда терминал / поток по-прежнему не может кодировать все встречающиеся символы Unicode, и когда вы не хотите прерывать print
их только из-за этого, вы можете ввести поведение «кодирование с заменой» в переводящем файловом объекте.
Вот пример:
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()
Использование простых строковых литералов за пределами ascii в коде Python 2/2 + 3
Единственная веская причина изменить глобальную кодировку по умолчанию (только на UTF-8), я думаю, касается решения исходного кода приложения - а не из-за проблем с кодировкой потока ввода-вывода: для записи строковых литералов за пределами ascii в код без принудительного всегда использовать u'string'
экранирование в стиле Unicode. Это можно сделать довольно последовательно (несмотря на то, что говорится в статье anonbadger ), позаботившись об исходном коде Python 2 или Python 2 + 3, который последовательно использует простые строковые литералы ascii или UTF-8 - поскольку эти строки потенциально подвергаются молчанию. преобразование юникода и переход между модулями или, возможно, переход на стандартный вывод. Для этого предпочтите "# encoding: utf-8
"или ascii (без объявления). Измените или удалите библиотеки, которые по-прежнему очень глупо фатально полагаются на ошибки кодирования ascii по умолчанию за пределами chr # 127 (что сегодня редко).
И сделайте так при запуске приложения (и / или через sitecustomize.py) в дополнение к SmartStdout
схеме выше - без использования 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
Таким образом, строковые литералы и большинство операций (кроме итерации символов) работают комфортно, не думая о преобразовании в Unicode, как если бы был только Python3. Файловый ввод-вывод, конечно, всегда требует особого внимания к кодировкам - как и в Python3.
Примечание: простые строки затем неявно преобразуются из utf-8 в unicode in SmartStdout
перед преобразованием в кодирование выходного потока.