ПрограммированиеBackend разработчик

Объясните работу и особенности встроенного типа bytes в Python. Как и где он применяется, чем отличается от str, и какие тонкости важны при обработке бинарных данных?

Проходите собеседования с ИИ помощником Hintsage

Ответ.

История вопроса

C появлением Python 3 тип bytes стал основным для хранения и обработки бинарных данных, отделившись от строк (str). В Python 2 строки (str) могли содержать как текст, так и байты, что было причиной частых ошибок при обработке данных в разных кодировках.

Проблема

В повседневном программировании часто сталкиваемся с задачами передачи и хранения данных вне контекста текстовой информации — например, работа с файлами, сетевыми запросами и протоколами обмена. Для этого требуется явный, удобный и безопасный тип, который чётко отличает последовательность байтов от строковых данных.

Решение

Тип bytes в Python хранит неизменяемую последовательность байтов (целых чисел от 0 до 255) и может быть создан из литерала байтов (с префиксом b) либо через явное преобразование типов. Для безопасного и предсказуемого взаимодействия между строками (str) и байтами (bytes) используются методы .encode() и .decode(). При работе с файлами, сетями и различными бинарными протоколами bytes — основной выбор.

Пример кода:

# Создание объекта bytes b = b'hello' # Через литерал b2 = bytes([104, 101, 108, 108, 111]) # Из списка целых чисел # Преобразование str <=> bytes text = 'текст' bin_text = text.encode('utf-8') # str -> bytes back = bin_text.decode('utf-8') # bytes -> str # Пример с файлом with open('file.bin', 'rb') as f: data = f.read() # data: bytes

Ключевые особенности:

  • bytes — неизменяемый (immutable) контейнер для последовательности байтов.
  • Отличается от str: str хранит (Unicode) текст, bytes — бинарные данные.
  • Все операции преобразования требует явного указания кодировки.

Вопросы с подвохом.

Можно ли сконкатенировать bytes и str в одну переменную?

Нет, склеивание через + или f-строки не работает: если попытаться выполнить b'abc' + 'def', возникнет TypeError. Нужно явно преобразовывать типы.

Чем отличается bytes от bytearray?

bytes — неизменяемый тип, то есть содержимое нельзя изменить после создания. bytearray — изменяемый вариант, поддерживает методы изменения байтов на месте.

b = bytes([1, 2, 3]) # immutable ba = bytearray([1, 2, 3]) # mutable ba[0] = 99 # OK b[0] = 99 # TypeError

Как узнать, сколько байт займет строка при конверсии через encode()?

Количество байт зависит от кодировки. Например, для 'abc' в utf-8 это 3 байта, а 'Привет' — 12. Только после вызова encode() можно узнать точный размер через len():

s = 'Привет' # 6 букв b = s.encode('utf-8') # 12 байт print(len(b)) # 12

Типовые ошибки и анти-паттерны

  • Путать bytes и str, передавать строку туда, где ожидаются байты (например, HTTP-запросы, бинарные файлы), или наоборот.
  • Забывать явно декодировать байты при записи в текстовый файл или выводе.
  • Сравнивать bytes и str напрямую — всегда False.

Пример из жизни

Негативный кейс

Разработчик читает файл в режиме 'rb' (байтовый) и пытается сразу обработать его как строку:

with open('file.txt', 'rb') as f: for line in f: print(line.strip()) # line: bytes

Плюсы:

  • Может сработать для ASCII-документов.

Минусы:

  • Для Unicode-файлов невозможна обработка без расшифровки через decode().
  • Возникают ошибки при попытке конкатенации с str.

Позитивный кейс

Разработчик обрабатывает байтовые потоки через decode(), вводит контроль кодировки:

with open('file.txt', 'rb') as f: for line in f: print(line.decode('utf-8').strip())

Плюсы:

  • Код работает для любых текстовых файлов в корректной кодировке.
  • Предсказуемое поведение при обработке и выводе.

Минусы:

  • Появляется дополнительная ответственность за явный выбор кодировки.
  • Дополнительная обработка ошибок при неправильной декодировке.