Ответ 1
Python 3 обрабатывает строки немного иначе. Первоначально был только один тип для
строки: str
. Когда юникод приобрел сцепление в 90-х годах, новый тип unicode
был добавлен для обработки Unicode без нарушения существующего кода 1. Это
эффективно, так же как str
, но с поддержкой многобайтов.
В Python 3 существуют два разных типа:
- Тип
bytes
. Это всего лишь последовательность байтов, Python не знает что-то о том, как интерпретировать это как символы. - Тип
str
. Это также последовательность байтов, но Python знает, как интерпретировать эти байты как символы. - Отключен отдельный тип
unicode
.str
теперь поддерживает unicode.
В Python 2 неявно предполагается, что кодирование может вызвать множество проблем; вы
может закончиться неправильным кодированием, или данные могут не иметь кодировки в
все (например, изображение PNG).
Явно говорю Python, какую кодировку использовать (или явно сообщая
догадка) часто намного лучше и намного больше соответствует "философии Питона",
из явного лучше, чем неявное.
Это изменение несовместимо с Python 2, поскольку многие возвращаемые значения изменились,
приводя к таким тонким проблемам, как этот; это, вероятно, главная причина, почему
Принятие Python 3 было настолько медленным. Поскольку Python не имеет статического ввода 2
невозможно автоматически изменить это с помощью script (например, в комплекте
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 Да, вы можете использовать аннотации функций, но это сравнительно новая функция и мало используется.