Подтвердить что ты не робот

Запись строк unicode через sys.stdout в Python

Предположим на мгновение, что нельзя использовать print (и, таким образом, воспользоваться возможностью автоматического обнаружения кодирования). Итак, это оставляет нас с sys.stdout. Тем не менее, sys.stdout настолько тупо, что не делает никакого разумного кодирования.

Теперь читаем страницу вики Python PrintFails и отправляем попробовать следующий код:

$ python -c 'import sys, codecs, locale; print str(sys.stdout.encoding); \
  sys.stdout = codecs.getwriter(locale.getpreferredencoding())(sys.stdout);

Однако это тоже не работает (по крайней мере, на Mac). Слишком понятно, почему:

>>> import locale
>>> locale.getpreferredencoding()
'mac-roman'
>>> sys.stdout.encoding
'UTF-8'

(UTF-8 - это то, что понимает один терминал).

Таким образом, один из приведенных выше вариантов кода:

$ python -c 'import sys, codecs, locale; print str(sys.stdout.encoding); \
  sys.stdout = codecs.getwriter(sys.stdout.encoding)(sys.stdout);

И теперь строки unicode отправляются правильно на sys.stdout и, следовательно, правильно печатаются на терминале (sys.stdout подключен терминал).

Является ли это правильным способом записи строк в unicode в sys.stdout или я должен делать что-то еще?

РЕДАКТИРОВАТЬ: время от времени, скажем, при прокладке на выходе less - sys.stdout.encoding будет None. в этом случае вышеуказанный код не будет выполнен.

4b9b3361

Ответ 1

Мне непонятно, почему вы не сможете печатать; но, полагая, да, подход выглядит для меня правильным.

Ответ 2

export PYTHONIOENCODING=utf-8

выполнит задание, но не сможет установить его на самом python...

что мы можем сделать, это проверить, не задано ли значение и сообщить пользователю установить его перед вызовом script с помощью

if __name__ == '__main__':
    if (sys.stdout.encoding is None):
        print >> sys.stderr, "please set python env PYTHONIOENCODING=UTF-8, example: export PYTHONIOENCODING=UTF-8, when write to stdout."
        exit(1)

Ответ 3

Лучше всего проверить, подключены ли вы напрямую к терминалу. Если да, используйте терминальную кодировку. В противном случае используйте предпочтительную кодировку системы.

if sys.stdout.isatty():
    default_encoding = sys.stdout.encoding
else:
    default_encoding = locale.getpreferredencoding()

Также очень важно всегда указывать пользователю какую кодировку она хочет. Обычно я делаю это командной строкой (например, -e ENCODING) и анализирую ее с помощью модуля optparse.

Еще одна хорошая вещь - не перезаписать sys.stdout с помощью автоматического кодера. Создайте свой кодер и используйте его, но оставьте sys.stdout в покое. Вы можете импортировать сторонние библиотеки, которые записывают закодированные байты непосредственно в sys.stdout.

Ответ 4

Существует необязательная переменная среды "PYTHONIOENCODING", которая может быть установлена ​​на желаемую кодировку по умолчанию. Это был бы один из способов захвата желаемой пользователем кодировки способом, совместимым со всем Python. Он похоронен в руководстве Python здесь.

Ответ 5

Это то, что я делаю в своем приложении:

sys.stdout.write(s.encode('utf-8'))

Это точное противоположное исправление для чтения имен UTF-8 из argv:

for file in sys.argv[1:]:
    file = file.decode('utf-8')

Это очень уродливо (IMHO), поскольку это заставляет вас работать с UTF-8.., что является нормой на Linux/Mac, но не на окнах... Работает для меня в любом случае:)