По-перше: reload(sys)
і встановити деяке випадкове кодування за замовчуванням лише стосовно потреби вихідного термінального потоку - це погана практика. reload
часто змінює речі в sys, які були створені залежно від навколишнього середовища - наприклад, sys.stdin / stdout потоки, sys.excepthook тощо.
Вирішення проблеми кодування на stdout
Найкраще, що я знаю, для вирішення проблеми кодування print
'ing-рядків unicode і поза-ascii str
' s (наприклад, від літералів) на sys.stdout: це подбати про sys.stdout (файл-подібний об'єкт), який здатний і необов'язково толерантний щодо потреб:
Коли sys.stdout.encoding
це None
з якої - то причини, або неіснуючого, або помилково помилкової або «менше» , ніж стандартний висновок терміналу або потік дійсно здатний, а потім спробувати забезпечити правильний .encoding
атрибут. Нарешті, замінивши sys.stdout & sys.stderr
перекладений файлоподібним об’єктом.
Коли термінал / потік все ще не може кодувати всі зустрічаються символи unicode, і коли ви не хочете зламати 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()
Використання звичайних рядкових літералів, що перевищують ascii, в коді Python 2/2 + 3
Єдина вагома причина зміни глобального кодування за замовчуванням (лише на UTF-8) Я думаю, що стосується рішення вихідного коду програми - а не через проблеми кодування потоку вводу / виводу: Для запису літеральних рядків, що перебувають поза ascii, у код без примусу завжди використовувати u'string'
уникнути стилю Unicode. Це можна зробити досить послідовно (незважаючи на те, що йдеться у статті Anonbadger ), піклуючись про основу вихідного коду Python 2 або Python 2 + 3, яка послідовно використовує лінійні рядки ascii або UTF-8 послідовно - наскільки ці рядки потенційно проходять беззвучно перетворення unicode та переміщення між модулями або потенційно перейти до stdout. Для цього віддайте перевагу "# 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
перш ніж перетворюються на вихідний потік.