Эта проблема обычно возникает при переключении с py2 на py3. В py2 plaintext
используется тип string и байтовый массив . В py3 plaintext
есть только строка , а метод outfile.write()
фактически принимает массив байтов , когда outfile
открывается в двоичном режиме, поэтому возникает исключение. Измените ввод на plaintext.encode('utf-8')
, чтобы решить проблему. Читайте дальше, если это вас беспокоит.
В py2 объявление для file.write создает впечатление, что вы передали строку: file.write(str)
. На самом деле вы передавали байтовый массив, вы должны были прочитать объявление так: file.write(bytes)
. Если вы читаете это так, проблема проста: file.write(bytes)
нужен тип байтов , а в py3 для получения байтов из str вы конвертируете его:
py3>> outfile.write(plaintext.encode('utf-8'))
Почему документы py2 объявили, что file.write
взяла строку? Ну, в py2 различие в объявлении не имело значения, потому что:
py2>> str==bytes #str and bytes aliased a single hybrid class in py2
True
Класс py2 str-bytes имеет методы / конструкторы, которые в некоторых отношениях ведут себя как класс строк, а в других - как класс байтовых массивов. Удобно для file.write
не так ли?:
py2>> plaintext='my string literal'
py2>> type(plaintext)
str #is it a string or is it a byte array? it's both!
py2>> outfile.write(plaintext) #can use plaintext as a byte array
Почему py3 сломал эту замечательную систему? Ну, потому что в py2 основные строковые функции не работали для остального мира. Измерить длину слова не-ASCII символом?
py2>> len('¡no') #length of string=3, length of UTF-8 byte array=4, since with variable len encoding the non-ASCII chars = 2-6 bytes
4 #always gives bytes.len not str.len
Все это время, когда вы думали, что просите len строки в py2, вы получали длину байтового массива из кодировки. Эта двусмысленность является фундаментальной проблемой классов с двумя обязанностями. Какую версию любого вызова метода вы реализуете?
Хорошая новость в том, что py3 решает эту проблему. Он разбивает классы str и bytes . Класс str имеет строковые методы, отдельный класс bytes имеет методы байтового массива:
py3>> len('¡ok') #string
3
py3>> len('¡ok'.encode('utf-8')) #bytes
4
Надеюсь, знание этого поможет разобраться в проблеме и немного облегчит перенос боли.