Строки против последовательности байт

Байты - это байты; символы - это абстракция. Неизменяемая последовательность Unicode символов называется строкой (string). Неизменяемая последовательность чисел-от-0-до-255 называется объект bytes.

>>> by = b'abcd\x65' ①
>>> by
b'abcde'
>>> type(by) ②
<class 'bytes'>
>>> len(by) ③
5
>>> by += b'\xff' ④
>>> by
b'abcde\xff'
>>> len(by) ⑤
6
>>> by[0] ⑥
97
>>> by[0] = 102 ⑦
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'bytes' object does not support item assignment

  • ① Чтобы создать объект bytes используйте синтаксис "байтовых строк" b''. Каждый байт в байтовой строке может быть либо ASCII символом, либо закодированным шестнадцатеричным числом от \x00 до \xff (0-255).
  • ② Тип байтовой строки - bytes.
  • ③ По аналогии со списками и строками, Вы можете определить длину байтовой строки с помощью встроенной функции len().
  • ④ По аналогии со списками и строками, Вы можете объединять байтовые строки с помощью оператора +. Результат будет новым объектом с типом bytes.
  • ⑤ Объединение 5-байтового и однобайтового объекта даст в результате 6-ти байтовый объект.
  • ⑥ По аналогии со списками и строками, Вы можете получить конкретный байт из байтовой строки по его индексу. Элементами обычной строки выступают строки, а элементами байтовой строки являются целые числа. Конкретно числа от 0 до 255.
  • ⑦ Байтовая строка неизменяемая. Вы не можете изменять какие-либо байты в ней. Если у Вас возникла необходимость изменить отдельные байты, то Вы можете либо использовать оператор конкатенации (+), который действует так же, как и со строками, либо конвертировать объект bytes в объект bytearray.

 

>>> by = b'abcd\x65'
>>> barr = bytearray(by) ①
>>> barr
bytearray(b'abcde')
>>> len(barr) ②
5
>>> barr[0] = 102 ③
>>> barr
bytearray(b'fbcde')

  • ① Для конвертирования объекта bytes в изменяемый объект bytearray используйте встроенную функцию bytearray().
  • ② Все методы и операторы, которые Вы использовали с объектами типа bytes, также подходят к объектам bytearray.
  • ③ Единственное отличие состоит в том, что Вы можете изменить значение отдельного байта при работе с объектом bytearray. Записываемое значение должно быть целым числом от 0 до 255.

Единственное, чего Вы не можете делать, это смешивать байты и строки.

>>> by = b'd'
>>> s = 'abcde'
>>> by + s ①
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: can't concat bytes to str
>>> s.count(by) ②
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: Can't convert 'bytes' object to str implicitly
>>> s.count(by.decode('ascii')) ③
1

  • ① нельзя соеденить байты и строку. Эта два разных типа данных.
  • ② Вы не можете подсчитать частоту встречаемости последовательности байтов в строке, потому что в строке вообще нет байтов. Строка - это последовательность символов. Возможно Вы имеете в виду "подсчитать количество вхождений строки, полученной докодированием последовательности байт из конкретной кодировки"? Тогда это необходимо указать точно. Python 3 не будет автоматически конвертировать байты в строки или строки в байты.
  • ③ По случайному совпадению это строка кода означает "подсчитать количество вхождений строки, полученной декодированием последовательности байт из конкретной кодировки".


Здесь появляется связь между строками и байтами: объект типа bytes имеет метод decode(), аргументом которого является кодировка, и который возвращает строку. В свою очередь строка имеет метод encode(), аргументом которого является кодировка, и который возвращает объект bytes. В предыдущем примере декодирование было относительно простым: последовательность байт в кодировке ASCII преобразовывалась в строку. Но этот процесс подходит для любой кодировки, которая поддерживает символы строки, даже устаревшие (не-Unicode) кодировки.

>>> a_string = '深入 Python' ①
>>> len(a_string)
9
>>> by = a_string.encode('utf-8') ②
>>> by
b'\xe6\xb7\xb1\xe5\x85\xa5 Python'
>>> len(by)
13
>>> by = a_string.encode('gb18030') ③
>>> by
b'\xc9\xee\xc8\xeb Python'
>>> len(by)
11
>>> by = a_string.encode('big5') ④
>>> by
b'\xb2`\xa4J Python'
>>> len(by)
11
>>> roundtrip = by.decode('big5') ⑤
>>> roundtrip
'深入 Python'
>>> a_string == roundtrip
True