Послідовності бінарних даних
Основні вбудовані класи для роботи з послідовностями бінарних даних в Python — це bytes
і bytearray
.
bytes
Байти — немутабельна послідовність окремих байт (чисел у діапазоні від 0 до 255).
Оскільки більшість основних бінарних протоколів базуються на кодуванні тексту ASCII, об'єкти байтів працюють з ASCII-сумісними символами і це нагадує роботу з символьними рядками. Синтаксис для літералів байтів в значній мірі такий же, як і для літералів символьного рядка, за винятком того, що додається префікс b
:
>>> b = b'Hi there!'
>>> b
b'Hi there!'
>>>
Допускаються лише ASCII-символи, тобто значення до 127 включно:
>>> b = b'Привіт!'
File "<stdin>", line 1
SyntaxError: bytes can only contain ASCII literal characters.
>>>
Інші значення задаються у шістнадцятковій системі числення, до значення додається префікс \x
:
>>> b = b'\x00\xff'
>>> b
b'\x00\xff'
>>> b[0]
0
>>> b[1]
255
>>>
"Сирі" байти (аналогічно "сирим" рядкам) теж допускаються:
>>> b = rb'\n'
>>> b
b'\\n'
>>>
Створити байтову послідовність можна за допомогою конструктора класа вказавши її довжину, при цьому створена послідовність буде заповнена значенням 0
:
>>> b = bytes(5)
>>> b
b'\x00\x00\x00\x00\x00'
>>>
Також можна передати конструктору ітерабельний об'єкт цілих чисел:
>>> b = bytes(range(5))
>>> b
b'\x00\x01\x02\x03\x04'
>>>
Можна створити послідовність байт з символьного рядка, для цього треба вказати кодування, в якому ми хочемо отримати наш рядок:
>>> b = bytes('ї', encoding='UTF-8')
>>> b
b'\xd1\x97'
>>>
Клас bytes
має метод fromhex()
який дозволяє створити об'єкт з символьного рядка. Рядок повинен складатись з пар шістнадцяткових цифр, пробіли ігноруються:
>>> bytes.fromhex('41f0 F1f2 ')
b'A\xf0\xf1\xf2'
>>>
Є також метод який виконує "зворотню дію" — повертає шістнадцяткове представленя байтового об'єкта як символьний рядок:
>>> b'A\xf0\xf1\xf2'.hex()
'41f0f1f2'
>>>
Ще один важливий метод класа bytes
:
decode(encoding="utf-8", errors="strict")
Метод декодує послідовність байт з вказаного кодування у символьний рядок:
>>> b = b'\xd0\x92\xd1\x96\xd1\x82\xd0\xb0\xd1\x8e!'
>>> b.decode()
'Вітаю!'
>>>
Другий параметр цього метода вказує, що робити якщо під час декодування відбувається помилка. Значення за замовчуванням strict
означає, що у разі виникнення помилки буде піднято виняток UnicodeError
. Також за допомогою цього параметра можна вказати, що усі помилки декодування будуть ігноруватись, замінятись на певний символ, інше (докладніше — читайте у документації Python).
Як ви могли вже зауважити, в залежності від значення кожного байта застосовуються різні способи відображення:
- для байтів з діапазона символів ASCII, які мають графічне відображення — від пробіла до
~
— выводится сам символ ASCII. - для байтів, які відповідають символам табуляції, нового рядка, бекслеш та інших виводяться відповідні ескейп-послідовності.
- для решти байтів виводиться шістнадцяткове представлення, наприклад
\x00
.
bytes
підтримує усі методи str
крім тих, що стосуються форматування (format, format_map), і ще декількох, які напряму залежать від особливостей Unicode, у тому числі casefold, isdecimal, isidentifier, isnumeric, isprintable і encode.
Це означає, що при работі з бінарними послідовностями ми можемо користуватись знайомими методами символьних рядків, наприклад endswith, replace, strip, upper і десятками інших, тільки аргументи мають бути типу bytes
, а не str
.
bytearray
Масив байтів — мутабельна послідовність окремих байт (чисел у діапазоні від 0 до 255).
Головна відмінність масива байтів від байт — це те, що перша є мутабельною послідовністю. Отже ми можемо використовувати усі методи, які властиві мутабельним послідовностям:
>>> b = bytearray(3)
>>> b.insert(0,65)
>>> b
bytearray(b'A\x00\x00\x00')
>>> b.append(65)
>>> b
bytearray(b'A\x00\x00\x00A')
>>> b.pop()
65
>>> b
bytearray(b'A\x00\x00\x00')
>>> b.reverse()
>>> b
bytearray(b'\x00\x00\x00A')
>>> b.remove(65)
>>> b
bytearray(b'\x00\x00\x00')
>>>