struct — Интерпретация байтов как упакованные двоичные данные


Модуль выполняет преобразования между Python значениями и C структурами, представленными как bytes объекты Python. Может использоваться для обработки двоичных данных, хранящихся в файлах или из сетевых подключений, а также из других источников. Он использует Строки формата в качестве компактного описания макета структур C и предполагаемого преобразования в/из значений Python.

Примечание

По умолчанию результат упаковки данной C структуры включает в себя байты заполнения, чтобы поддерживать правильное выравнивание для задействованных типов C; аналогично учитывается выравнивание при распаковке. Это поведение выбрано таким образом, чтобы байты упакованной структуры точно соответствовали разметке в памяти соответствующей структуры C. Чтобы обрабатывать независимые от платформы форматы данных или пропускать неявные байты заполнения, используется размер и выравнивание standard вместо размера и выравнивания native: подробности см. в Порядок байтов, размер и выравнивание.

Некоторые функции struct (и методы Struct) принимают buffer аргумент. Это относится к объектам, которые реализуют Буферный протокол и предоставляют буфер с возможностью чтения или записи и чтения. Наиболее распространенными типами, используемыми для этой цели, являются bytes и bytearray, но многие другие типы, которые можно рассматривать как массив байтов, реализуют протокол буфера, так что их можно читать/заполнять без дополнительного копирования из объекта bytes.

Функции и исключения

Модуль определяет следующие исключения и функции:

exception struct.error

Исключения возникшие по разным причинам; аргумент — это строка, рассказывающая, что не так.

struct.pack(format, v1, v2, ...)

Возвращает байтовый объект, содержащий значения v1, v2, …, упакованные в соответствии со строкой формата format. Аргументы должны точно соответствовать значениям, требуемым форматом.

struct.pack_into(format, buffer, offset, v1, v2, ...)

Упаковать значения v1, v2, … в соответствии со строкой формата format и записать упакованные байты в записываемый буфер buffer, начиная с позиции offset. Обратите внимание, что offset является обязательным аргументом.

struct.unpack(format, buffer)

Распаковать из буфера buffer (предположительно упакованного pack(format, ...)) в соответствии со строкой формата format. Результатом будет кортеж, даже если он содержит ровно один элемент. Размер буфера в байтах должен соответствовать размеру, требуемому форматом, как это отражено в calcsize().

struct.unpack_from(format, buffer, offset=0)

Распаковывает из buffer, начиная с позиции offset, в соответствии со строкой формата format. Результатом будет кортеж, даже если он содержит ровно один элемент. Размер буфера в байтах, начиная с позиции offset, должен быть не меньше размера, требуемого форматом, как это отражено в calcsize().

struct.iter_unpack(format, buffer)

Итеративно распаковывает из буфера buffer согласно строке формата format. Функция возвращает итератор, который будет читать куски одинакового размера из буфера до тех пор, пока всё его содержимое не будет использовано. Размер буфера в байтах должен быть кратен размеру, требуемому форматом, как это отражено в calcsize().

Каждая итерация отдаёт кортеж, указанный в строке формата.

Добавлено в версии 3.4.

struct.calcsize(format)

Возвращает размер структуры (и, следовательно, объекта байтов, созданного pack(format, ...)), соответствующего строке формата format.

Строки формата

Строки формата — это используемый механизм для указания ожидаемого макета при упаковке и распаковке данных. Они создаются из Форматные символы, определяющие тип данных, которые должны быть упакованы/распакованы. Кроме того, есть специальные символы для управления Порядок байтов, размер и выравнивание.

Порядок байтов, размер и выравнивание

По умолчанию типы C представлены в родном формате и порядке байтов компьютера, а также если это необходимо, выравниваются путём пропуска байтов набивки (pad) (в соответствии с правилами, используемыми C компилятором).

В качестве альтернативы, первый символ строки формата может использоваться для указания порядка байтов, размера и выравнивания упакованных данных в соответствии со следующей таблицей:

Символ Порядок байтов Размер Выравнивание
@ родной родной родной
= родной стандарт никакого
< little-endian стандарт никакого
> big-endian стандарт никакого
! сеть (= big-endian) стандарт никакого

Если первый символ не является одним из них, предполагается '@'.

Родной порядок байтов — big-endian (от старшего к младшему) или little-endian (от младшего к старшему) байтов, в зависимости от хост-системы. Например, у Intel x86 и AMD64 (x86-64) little-endian; у Motorola 68000 и PowerPC G5 big-endian порядок байтов; ARM и Intel Itanium поддерживают переключаемый порядок следования байтов (bi-endian). Используйте sys.byteorder, чтобы проверить порядок байтов в вашей системе.

Родной размер и выравнивание определяются с помощью выражения sizeof компилятора C. Он всегда сочетается с родным порядком байтов.

Стандартный размер зависит только от форматного символа; см. таблицу в разделе Форматные символы.

Обратите внимание на разницу между '@' и '=': оба используют родной порядок байтов, но размер и выравнивание последнего стандартизированы.

Форма '!' представляет сетевой порядок байтов, который всегда является big-endian порядком байтов, как определено в IETF RFC 1700.

Невозможно указать неродной порядок байтов (принудительная замена байтов); используйте соответствующий выбор '<' или '>'.

Примечания:

  1. Заполнение автоматически добавляется только между последовательными членами структуры. Заполнение не добавляется ни в начале, ни в конце закодированной структуры.
  2. При использовании нестандартного размера и выравнивания отступы не добавляются, например с «<», «>», «=» и «!».
  3. Чтобы выровнять конец структуры в соответствии с требованием выравнивания определенного типа, завершите формат кодом для этого типа с нулевым числом повторений. См. Примеры.

Форматные символы

У форматные символы выполняют преобразование между значениями C и Python очевидным образом, с учётом их типов. Столбец «Стандартный размер» относится к размеру упакованного значения в байтах при использовании стандартного размера; т. е., когда строка формата начинается с одного из '<', '>', '!' или '='. При использовании родного размера размер упакованного значения зависит от платформы.

Формат C Тип Python тип Стандартный размер Примечания
x байт набивки нет значения    
c char байты длины 1 1  
b signed char integer 1 (1), (2)
B unsigned char integer 1 (2)
? _Bool bool 1 (1)
h short integer 2 (2)
H unsigned short integer 2 (2)
i int integer 4 (2)
I unsigned int integer 4 (2)
l long integer 4 (2)
L unsigned long integer 4 (2)
q long long integer 8 (2)
Q unsigned long long integer 8 (2)
n ssize_t integer   (3)
N size_t integer   (3)
e (6) float 2 (4)
f float float 4 (4)
d double float 8 (4)
s char[] bytes    
p char[] bytes    
P void * integer   (5)

Изменено в версии 3.3: Добавлена поддержка 'n' и 'N' форматов.

Изменено в версии 3.6: Добавлена поддержка 'e' формата.

Примечания:

  1. Код преобразования '?' соответствует типу _Bool, определенному C99. Если этот тип недоступен, он моделируется с помощью char. В стандартном режиме он всегда представлен одним байтом.

  2. При попытке упаковать нецелое число с использованием любого из кодов преобразования целого числа, то вызывается метод __index__() для преобразования аргумента в целое число перед упаковкой, если у нецелого числа есть данный метод.

    Изменено в версии 3.2: Использование метода __index__() для нецелых чисел является новым в 3.2.

  3. Коды преобразования 'n' и 'N' доступны только для родного размера (выбранного по умолчанию или с символом порядка байтов '@'). Для стандартного размера вы можете использовать любой другой целочисленный формат, подходящий для вашего приложения.

  4. Для кодов преобразования 'f', 'd' и 'e' упакованное представление использует формат IEEE 754 binary32, binary64 или binary16 (для 'f', 'd' или 'e' соответственно), независимо от формата с плавающей запятой, используемого платформой.

  5. Символ формата 'P' доступен только для родного порядка байтов (выбран по умолчанию или с символом порядка байтов '@'). Символ порядка байтов '=' выбирает использование little- или big-endian порядка байтов в зависимости от хост-системы. Модуль struct не интерпретирует его как собственный порядок, поэтому формат 'P' недоступен.

  6. Тип IEEE 754 binary16 «половинной точности» был введён в редакции 2008 года Стандарта IEEE 754. У него есть знаковый бит, 5-битная экспонента и 11-битная точность (с явно сохраненными 10 битами) и может представлять числа между приблизительно 6.1e-05 и 6.5e+04 с полной точностью. Данный тип широко не поддерживается компиляторами C: на типичной машине беззнаковое сокращение можно использовать для хранения, но не для математических операций. См. страницу Википедии о форматах с плавающей запятой половинной точности для получения дополнительной информации.

Форматному символу может предшествовать целое число повторов. Например, строка формата '4h' означает то же самое, что и 'hhhh'.

Пробелы между форматами игнорируются; однако счетчик и его формат не должны содержать пробелов.

Для символа формата 's' счётчик интерпретируется как длина байтов, а не как счётчик повторов, как для других форматных символов; например, '10s' означает одну 10-байтовую строку, а '10c' означает 10 символов. Если счётчик не указан, по умолчанию он равен 1. Для упаковки строка усекается или дополняется нулевыми байтами, чтобы она соответствовала размеру. Для распаковки у результирующего объекта байтов всегда будет точно указанное количество байтов. В особом случае '0s' означает одну пустую строку (в то время как '0c' означает 0 символов).

При упаковке значения x с использованием одного из целочисленных форматов ('b', 'B', 'h', 'H', 'i', 'I', 'l', 'L', 'q', 'Q'), если x выходит за пределы допустимого диапазона для этого формата, тогда возникает struct.error.

Изменено в версии 3.1: В версии 3.0 некоторые целочисленные форматы обёрнуты значениями, выходящие за пределы допустимого диапазона поднимали DeprecationWarning вместо struct.error.

Символ формата 'p' кодирует «Pascal строку», означающую короткую строку переменной длины, хранящуюся в фиксированном количестве байтов, заданную счётчиком. Первый сохраненный байт — это длина строки или 255, в зависимости от того, что меньше. Далее следуют байты строки. Если строка, переданная в pack(), слишком длинная (длиннее, чем счетчик минус 1), сохраняются только начальные байты count-1 строки. Если строка короче, чем count-1, она дополняется нулевыми байтами, чтобы использовалось точное количество байтов. Обратите внимание, что для unpack() форматный символ 'p' занимает count байтов, но возвращаемая строка никогда не может содержать более 255 байтов.

Для форматного символа '?' возвращаемое значение — True или False. При упаковке используется значение истинности объекта аргумента. Будут упаковываться либо 0, либо 1 в родном или стандартном логическом представлении, и любое ненулевое значение при распаковке будет True.

Примеры

Примечание

Все примеры предполагают родной порядок байтов, размер и выравнивание с big-endian порядком байт.

Базовый пример упаковки/распаковки трёх целых чисел:

>>> from struct import *
>>> pack('hhl', 1, 2, 3)
b'\x00\x01\x00\x02\x00\x00\x00\x03'
>>> unpack('hhl', b'\x00\x01\x00\x02\x00\x00\x00\x03')
(1, 2, 3)
>>> calcsize('hhl')
8

Распакованным полям можно присвоить имена, назначив их переменным или заключив результат в именованный кортеж:

>>> record = b'raymond   \x32\x12\x08\x01\x08'
>>> name, serialnum, school, gradelevel = unpack('<10sHHb', record)

>>> from collections import namedtuple
>>> Student = namedtuple('Student', 'name serialnum school gradelevel')
>>> Student._make(unpack('<10sHHb', record))
Student(name=b'raymond   ', serialnum=4658, school=264, gradelevel=8)

Порядок символов формата может повлиять на размер, поскольку отличается заполнение, необходимое для удовлетворения требований к выравниванию:

>>> pack('ci', b'*', 0x12131415)
b'*\x00\x00\x00\x12\x13\x14\x15'
>>> pack('ic', 0x12131415, b'*')
b'\x12\x13\x14\x15*'
>>> calcsize('ci')
8
>>> calcsize('ic')
5

Следующий формат 'llh0l' определяет два байта заполнения в конце, предполагая, что длинные значения выровнены по 4-байтовым границам:

>>> pack('llh0l', 1, 2, 3)
b'\x00\x00\x00\x01\x00\x00\x00\x02\x00\x03\x00\x00'

Это работает только тогда, когда действуют родной размер и выравнивание; стандартный размер и выравнивание не требуют выравнивания.

См.также

Модуль array
Упакованное двоичное хранилище однородных данных.
Модуль xdrlib
Упаковка и распаковка XDR данных.

Классы

Модуль struct также определяет следующий тип:

class struct.Struct(format)

Возвращает новый объект Struct, который записывает и считывает двоичные данные в соответствии со строкой формата format. Создание объекта Struct один раз и вызов его методов более эффективен, чем вызов функций struct с тем же форматом, поскольку строку формата нужно скомпилировать только один раз.

Примечание

Скомпилированные версии самых последних строк формата, переданных в Struct, и функции уровня модуля кэшируются, поэтому программам, использующим только несколько строк формата, не нужно беспокоиться о повторном использовании одного экземпляра Struct.

Скомпилированные объекты Struct поддерживают следующие методы и атрибуты:

pack(v1, v2, ...)

Идентично функции pack() с использованием скомпилированного формата. (len(result) будет равняться size.)

pack_into(buffer, offset, v1, v2, ...)

Идентично функции pack_into() с использованием скомпилированного формата.

unpack(buffer)

Идентично функции unpack() с использованием скомпилированного формата. Размер буфера в байтах должен быть равен size.

unpack_from(buffer, offset=0)

Идентичен функции unpack_from() с использованием скомпилированного формата. Размер буфера в байтах, начиная с позиции offset, должен быть не менее size.

iter_unpack(buffer)

Идентично функции iter_unpack() с использованием скомпилированного формата. Размер буфера в байтах должен быть кратным size.

Добавлено в версии 3.4.

format

Строка формата, используемая для создания этого объекта Struct.

Изменено в версии 3.7: Тип форматной строки теперь str вместо bytes.

size

Вычисленный размер структуры (и, следовательно, объекта байтов, созданного методом pack()), соответствующего format.