Вопрос-Ответ

Setting the correct encoding when piping stdout in Python

Установка правильной кодировки при передаче стандартного вывода в Python

При передаче выходных данных программы на Python интерпретатор Python путается в кодировке и устанавливает для нее значение None . Это означает, что программа, подобная этой:

# -*- coding: utf-8 -*-
print u"åäö"

будет работать нормально при обычном запуске, но не сработает при:


Ошибка UnicodeEncodeError: кодек 'ascii' не может закодировать символ u '\ xa0' в позиции 0: порядковый номер не входит в диапазон (128)


при использовании в последовательности каналов.

Какой наилучший способ заставить это работать при передаче? Могу ли я просто сказать ему использовать любую кодировку, которую использует оболочка / файловая система / что угодно?

Предложения, которые я видел до сих пор, заключаются в том, чтобы изменить ваш site.py напрямую или жестко запрограммировать defaultencoding с помощью этого взлома:

# -*- coding: utf-8 -*-
import sys
reload(sys)
sys.setdefaultencoding('utf-8')
print u"åäö"

Есть ли лучший способ заставить конвейер работать?

Переведено автоматически
Ответ 1

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

Эмпирическое правило таково: всегда используйте Unicode внутри. Декодируйте то, что вы получаете, и кодируйте то, что вы отправляете.

# -*- coding: utf-8 -*-
print u"åäö".encode('utf-8')

Еще одним дидактическим примером является программа на Python для преобразования между ISO-8859-1 и UTF-8, делая все в верхнем регистре между ними.

import sys
for line in sys.stdin:
# Decode what you receive:
line = line.decode('iso8859-1')

# Work with Unicode internally:
line = line.upper()

# Encode what you send:
line = line.encode('utf-8')
sys.stdout.write(line)

Установка системной кодировки по умолчанию - плохая идея, потому что некоторые используемые вами модули и библиотеки могут полагаться на то, что это ASCII. Не делайте этого.

Ответ 2

Во-первых, относительно этого решения:

# -*- coding: utf-8 -*-
print u"åäö".encode('utf-8')

нецелесообразно каждый раз явно печатать с заданной кодировкой. Это было бы повторяющимся и чреватым ошибками.

Лучшим решением является изменение sys.stdout в начале вашей программы на кодирование с выбранной кодировкой. Вот одно решение, которое я нашел на Python: Как выбирается sys.stdout.encoding?, в частности комментарий "toka":

import sys
import codecs
sys.stdout = codecs.getwriter('utf8')(sys.stdout)
Ответ 3

Возможно, вы захотите попробовать изменить переменную среды "PYTHONIOENCODING" на "utf_8". Я написал страницу о моих испытаниях с этой проблемой.

Tl; dr из сообщения в блоге:

import sys, locale, os
print(sys.stdout.encoding)
print(sys.stdout.isatty())
print(locale.getpreferredencoding())
print(sys.getfilesystemencoding())
print(os.environ["PYTHONIOENCODING"])
print(chr(246), chr(9786), chr(9787))

дает вам

utf_8
False
ANSI_X3.4-1968
ascii
utf_8
ö ☺ ☻
Ответ 4
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)

Обновление для ответа на комментарий:
проблема существует только при передаче в стандартный вывод.
Я тестировал в Fedora 25 Python 2.7.13

python --version
Python 2.7.13

cat b.py

#!/usr/bin/env python
#-*- coding: utf-8 -*-
import sys

print sys.stdout.encoding

выполняется ./b.py

UTF-8

выполняется ./b.py | меньше

None
python