Python 3 TypeError: должен быть str, а не байтами с sys.stdout.write ()

Я искал способ запустить внешний процесс из сценария python и распечатать его сообщения stdout во время выполнения.
Приведенный ниже код работает, но не выводит вывод stdout во время выполнения. Когда он выходит, я получаю следующую ошибку:

sys.stdout.write (nextline) TypeError: должен быть str, а не байтами

p = subprocess.Popen(["demo.exe"],stdout = subprocess.PIPE, stderr= subprocess.PIPE) # Poll process for new output until finished while True: nextline = p.stdout.readline() if nextline == '' and p.poll() != None: break sys.stdout.write(nextline) sys.stdout.flush() output = p.communicate()[0] exitCode = p.returncode 

Я использую python 3.3.2

2 Solutions collect form web for “Python 3 TypeError: должен быть str, а не байтами с sys.stdout.write ()”

Python 3 обрабатывает строки немного иначе. Первоначально для строк был только один тип: str . Когда юникод приобрел тягу в 90-х, новый unicode тип был добавлен для обработки Unicode без нарушения существующего кода 1 . Это фактически то же самое, что и str но с поддержкой многобайтов.

В Python 3 существуют два разных типа:

  • Тип bytes . Это всего лишь последовательность байтов, Python ничего не знает о том, как интерпретировать это как символы.
  • Тип str . Это также последовательность байтов, но Python знает, как интерпретировать эти байты как символы .
  • Отдельный тип unicode был удален. str теперь поддерживает unicode.

В Python 2 неявно предполагается, что кодирование может вызвать множество проблем; вы можете использовать неправильную кодировку, или данные могут вообще не иметь кодировки (например, это изображение PNG).
Явно говорю, что Python, кодирование которого используется (или явно говорящее догадываться), часто намного лучше и намного больше соответствует «философии Python» « явный лучше, чем неявный ».

Это изменение несовместимо с Python 2, поскольку многие возвращаемые значения изменились, что приводит к таким тонким проблемам, как этот; вероятно, это основная причина, по которой принятие Python 3 было настолько медленным. Поскольку у Python нет статического ввода 2, это невозможно автоматически изменить с помощью скрипта (например, в комплекте 2to3 ).

  • Вы можете преобразовать str в bytes с bytes('h€llo', 'utf-8') ; это должно произвести b'H\xe2\x82\xacllo' . Обратите внимание, как один символ был преобразован в три байта.
  • Вы можете преобразовать bytes в str с помощью b'H\xe2\x82\xacllo'.decode('utf-8') .

Конечно, UTF-8 может быть неправильным набором символов в вашем случае, поэтому обязательно используйте правильный.

В вашем конкретном фрагменте кода nextline имеет тип bytes , а не str , чтение stdout и stdin из subprocess измененного в Python 3 от str до bytes . Это связано с тем, что Python не может быть уверен, какую кодировку он использует. Вероятно, он использует то же, что и sys.stdin.encoding (кодирование вашей системы), но это не может быть уверенным.

Вам необходимо заменить:

 sys.stdout.write(nextline) 

с:

 sys.stdout.write(nextline.decode('utf-8')) 

или, может быть:

 sys.stdout.write(nextline.decode(sys.stdout.encoding)) 

Вам также потребуется изменить, if nextline == '' if nextline == b'' поскольку:

 >>> '' == b'' False 

Также см. Python 3 ChangeLog , PEP 358 и PEP 3112 .


1 Есть несколько опрятных трюков, которые вы можете сделать с ASCII, которые вы не можете сделать с многобайтовыми наборами символов; наиболее известным примером является «xor с пространством для переключения случая» (например, chr(ord('a') ^ ord(' ')) == 'A' ) и «установить 6-й бит для создания контрольного символа» (например, ord('\t') + ord('@') == ord('I') ). ASCII был разработан в то время, когда манипулирование отдельными битами – это операция с незначительным воздействием на производительность.

2 Да, вы можете использовать аннотации функций, но это сравнительно новая функция и мало используется.

Хотя принятый ответ будет работать нормально, если байты, которые у вас есть из вашего подпроцесса, кодируются с использованием sys.stdout.encoding (или совместимое кодирование, например чтение из инструмента, который выводит ASCII, а ваш stdout использует UTF-8), правильный способ записать произвольные байты в stdout:

 sys.stdout.buffer.write(some_bytes_object) 

Это будет просто выводить байты как есть, не пытаясь рассматривать их как кодирование в некотором некотором кодировании.

  • Получение каждой нечетной переменной в списке?
  • Работа с db.Timeout в Google App Engine
  • Может ли sys.argv обрабатывать дополнительные аргументы?
  • dev_appserver.py: команда не найдена
  • Машинное обучение для серверов мониторинга
  • Не удалось импортировать модуль
  • Строка Python для Int или None
  • Python предлагает расширенный поиск строк с операторами и boolean
  • Python - лучший язык программирования в мире.