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