struct
— Интерпретируйте байты как упакованные двоичные данные¶
Источник: Lib/struct.py
Этот модуль конвертирует между значениями Python и структурами C, представленными как объекты Python bytes
. Компактные format strings описывают предполагаемые преобразования в/из значений Python. Функции и объекты модуля могут быть использованы для двух разных целей: обмена данными с внешними источниками (файлами или сетевыми соединениями) или передачи данных между приложением на Python и слоем C.
Примечание
Если префиксный символ не указан, по умолчанию используется режим native. Он упаковывает или распаковывает данные в зависимости от платформы и компилятора, на котором был создан интерпретатор Python. Результат упаковки данной C-структуры включает байты-заглушки, которые поддерживают правильное выравнивание для соответствующих C-типов; аналогичным образом выравнивание учитывается при распаковке. В отличие от этого, при передаче данных между внешними источниками программист отвечает за определение порядка следования байтов и прокладок между элементами. Подробности см. в разделе Порядок, размер и выравнивание байтов.
Некоторые функции struct
(и методы Struct
) принимают аргумент буфер. Это относится к объектам, реализующим Буферный протокол и предоставляющим буфер для чтения или записи. Чаще всего для этой цели используются типы bytes
и bytearray
, но многие другие типы, которые можно рассматривать как массив байтов, реализуют протокол буфера, так что их можно читать/заполнять без дополнительного копирования из объекта bytes
.
Функции и исключения¶
В модуле определены следующие исключения и функции:
- exception struct.error¶
Исключение, возникающее в различных случаях; аргумент - строка, описывающая, что именно не так.
- struct.pack(format, v1, v2, ...)¶
Возвращает объект bytes, содержащий значения 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)¶
Распаковать из буфера, начиная с позиции offset, в соответствии со строкой формата format. Результатом является кортеж, даже если он содержит ровно один элемент. Размер буфера в байтах, начиная с позиции offset, должен быть не меньше размера, требуемого форматом, что отражается
calcsize()
.
- struct.iter_unpack(format, buffer)¶
Итеративно распакуйте из буфера buffer в соответствии со строкой формата format. Эта функция возвращает итератор, который будет считывать из буфера одинаковые по размеру фрагменты, пока все его содержимое не будет израсходовано. Размер буфера в байтах должен быть кратен размеру, требуемому форматом, что отражается
calcsize()
.Каждая итерация выдает кортеж, заданный строкой формата.
Added in version 3.4.
- struct.calcsize(format)¶
Возвращает размер структуры (и, следовательно, объекта bytes, создаваемого
pack(format, ...)
), соответствующей строке формата format.
Строки формата¶
Строки формата описывают расположение данных при упаковке и распаковке. Они строятся из format characters, которые определяют тип упаковываемых/распаковываемых данных. Кроме того, специальные символы управляют byte order, size and alignment. Каждая строка формата состоит из необязательного префиксного символа, который описывает общие свойства данных, и одного или нескольких символов формата, которые описывают фактические значения данных и вставку.
Порядок, размер и выравнивание байтов¶
По умолчанию типы C представляются в собственном формате и порядке байтов машины, а также правильно выравниваются, пропуская при необходимости байты-заглушки (в соответствии с правилами, используемыми компилятором C). Такое поведение выбрано для того, чтобы байты упакованной структуры точно соответствовали разметке памяти соответствующей C-структуры. Использовать ли «родное» упорядочивание байтов и вставку байтов или стандартные форматы, зависит от приложения.
В качестве альтернативы, первый символ строки формата может использоваться для указания порядка байт, размера и выравнивания упакованных данных, в соответствии со следующей таблицей:
Персонаж |
Порядок байтов |
Размер |
Выравнивание |
---|---|---|---|
|
родной |
родной |
родной |
|
родной |
стандарт |
нет |
|
little-endian |
стандарт |
нет |
|
big-endian |
стандарт |
нет |
|
сеть (= big-endian) |
стандарт |
нет |
Если первый символ не является одним из них, предполагается '@'
.
Примечание
Число 1023 (0x3ff
в шестнадцатеричной системе) имеет следующие представления байтов:
03 ff
в big-endian (>
)ff 03
в little-endian (<
)
Пример из Python:
>>> import struct
>>> struct.pack('>h', 1023)
b'\x03\xff'
>>> struct.pack('<h', 1023)
b'\xff\x03'
Родной порядок байтов - big-endian или little-endian, в зависимости от хост-системы. Например, Intel x86, AMD64 (x86-64) и Apple M1 имеют little-endian; IBM z и многие устаревшие архитектуры имеют big-endian. Используйте sys.byteorder
, чтобы проверить эндианальность вашей системы.
Родной размер и выравнивание определяются с помощью выражения sizeof
компилятора C. Оно всегда сочетается с родным порядком байтов.
Стандартный размер зависит только от символа формата; см. таблицу в разделе Символы формата.
Обратите внимание на разницу между '@'
и '='
: оба используют собственный порядок байтов, но размер и выравнивание последнего стандартизированы.
Форма '!'
представляет порядок байтов в сети, который всегда является big-endian, как определено в IETF RFC 1700.
Не существует способа указать неродной порядок байтов (принудительная замена байтов); используйте соответствующий выбор '<'
или '>'
.
Примечания:
Подшивка автоматически добавляется только между последовательными членами структуры. В начале и в конце закодированной структуры добавление вставки не производится.
При использовании неродного размера и выравнивания, например, при использовании символов „<“, „>“, „=“ и „!“, добавление подкладки не производится.
Чтобы выровнять конец структуры в соответствии с требованиями выравнивания определенного типа, завершите формат кодом этого типа с нулевым числом повторений. См. Примеры.
Символы формата¶
Символы формата имеют следующее значение; преобразование между значениями C и Python должно быть очевидным, учитывая их типы. Столбец „Standard size“ означает размер упакованного значения в байтах при использовании стандартного размера; то есть когда строка формата начинается с одного из '<'
, '>'
, '!'
или '='
. При использовании родного размера размер упакованного значения зависит от платформы.
Формат |
Тип C |
Тип Python |
Стандартный размер |
Примечания |
---|---|---|---|---|
|
байт подложки |
нет значения |
(7) |
|
|
char |
байт длины 1 |
1 |
|
|
signed char |
целое число |
1 |
(1), (2) |
|
unsigned char |
целое число |
1 |
(2) |
|
_Bool |
bool |
1 |
(1) |
|
short |
целое число |
2 |
(2) |
|
unsigned short |
целое число |
2 |
(2) |
|
int |
целое число |
4 |
(2) |
|
unsigned int |
целое число |
4 |
(2) |
|
long |
целое число |
4 |
(2) |
|
unsigned long |
целое число |
4 |
(2) |
|
long long |
целое число |
8 |
(2) |
|
unsigned long long |
целое число |
8 |
(2) |
|
|
целое число |
(3) |
|
|
|
целое число |
(3) |
|
|
(6) |
float |
2 |
(4) |
|
float |
float |
4 |
(4) |
|
double |
float |
8 |
(4) |
|
char[] |
байты |
(9) |
|
|
char[] |
байты |
(8) |
|
|
void* |
целое число |
(5) |
Изменено в версии 3.3: Добавлена поддержка форматов 'n'
и 'N'
.
Изменено в версии 3.6: Добавлена поддержка формата 'e'
.
Примечания:
Код преобразования
'?'
соответствует типу _Bool, определенному в C99. Если этот тип недоступен, он моделируется с помощью char. В стандартном режиме он всегда представлен одним байтом.При попытке упаковать нецелое число с помощью любого из кодов преобразования целых чисел, если у нецелого числа есть метод
__index__()
, то этот метод вызывается для преобразования аргумента в целое число перед упаковкой.Изменено в версии 3.2: Добавлено использование метода
__index__()
для нецелых чисел.Коды преобразования
'n'
и'N'
доступны только для собственного размера (выбранного по умолчанию или с помощью символа порядка байтов'@'
). Для стандартного размера вы можете использовать любой другой целочисленный формат, подходящий для вашего приложения.Для кодов преобразования
'f'
,'d'
и'e'
упакованное представление использует формат IEEE 754 binary32, binary64 или binary16 (для'f'
,'d'
или'e'
соответственно), независимо от формата с плавающей точкой, используемого платформой.Символ формата
'P'
доступен только для собственного порядка байтов (выбранного по умолчанию или с помощью символа порядка байтов'@'
). Символ порядка байтов'='
выбирает, какой порядок байтов использовать - little- или big-endian - в зависимости от хост-системы. Модуль struct не интерпретирует это как собственное упорядочивание, поэтому формат'P'
недоступен.Тип IEEE 754 binary16 «половинной точности» был введен в 2008 году в ревизии IEEE 754 standard. Он имеет бит знака, 5-битную экспоненту и 11-битную точность (с явным сохранением 10 бит), и может представлять числа между приблизительно
6.1e-05
и6.5e+04
с полной точностью. Этот тип не очень широко поддерживается компиляторами языка Си: на типичной машине беззнаковое короткое число можно использовать для хранения, но не для математических операций. Более подробную информацию см. на странице Википедии, посвященной half-precision floating-point format.При упаковке
'x'
вставляет один байт NUL.Символ формата
'p'
кодирует «строку Паскаля», то есть короткую строку переменной длины, хранящуюся в фиксированном количестве байт, задаваемом счетчиком. Первый сохраненный байт - это длина строки или 255, в зависимости от того, что меньше. Далее следуют байты строки. Если строка, переданная вpack()
, слишком длинная (длиннее, чем счетчик минус 1), сохраняются только первыеcount-1
байта строки. Если строка корочеcount-1
, она заполняется нулевыми байтами, так что всего будет использовано ровно столько байт. Обратите внимание, что дляunpack()
символ формата'p'
занимаетcount
байт, но возвращаемая строка никогда не может содержать более 255 байт.Для символа формата
's'
счет интерпретируется как длина байта, а не как счетчик повторений, как для других символов формата; например,'10s'
означает одну 10-байтную строку, отображающуюся на одну байтную строку Python или из нее, в то время как'10c'
означает 10 отдельных однобайтовых элементов символов (например,cccccccccc
), отображающихся на десять различных байтовых объектов Python или из них. (Конкретную демонстрацию разницы см. в Примеры.) Если счетчик не указан, по умолчанию он равен 1. При упаковке строка усекается или заполняется нулевыми байтами, чтобы она поместилась. При распаковке результирующий объект bytes всегда содержит ровно указанное количество байтов. В качестве особого случая'0s'
означает одиночную пустую строку (в то время как'0c'
означает 0 символов).
Символу формата может предшествовать интегральный счетчик повторов. Например, строка формата '4h'
означает то же самое, что и 'hhhh'
.
Символы пробелов между форматами игнорируются; однако граф и его формат не должны содержать пробелов.
При упаковке значения x
с помощью одного из целочисленных форматов ('b'
, 'B'
, 'h'
, 'H'
, 'i'
, 'I'
, 'l'
, 'L'
, 'q'
, 'Q'
), если x
находится вне допустимого диапазона для данного формата, то происходит повышение значения struct.error
.
Изменено в версии 3.1: Ранее некоторые форматы целых чисел обворачивали значения, выходящие за пределы диапазона, и выводили DeprecationWarning
вместо struct.error
.
Для символа формата '?'
возвращаемым значением будет либо True
, либо False
. При упаковке используется истинностное значение объекта-аргумента. Упаковывается либо 0, либо 1 в родном или стандартном представлении bool, а при распаковке любое ненулевое значение будет True
.
Примеры¶
Примечание
Примеры нативного порядка байтов (обозначенные префиксом формата '@'
или отсутствием какого-либо префикса) могут не совпадать с тем, что выдает машина читателя, поскольку это зависит от платформы и компилятора.
Упаковывайте и распаковывайте целые числа трех разных размеров, используя упорядочивание big endian:
>>> from struct import *
>>> pack(">bhl", 1, 2, 3)
b'\x01\x00\x02\x00\x00\x00\x03'
>>> unpack('>bhl', b'\x01\x00\x02\x00\x00\x00\x03')
(1, 2, 3)
>>> calcsize('>bhl')
7
Попытка упаковать целое число, которое слишком велико для определенного поля:
>>> pack(">h", 99999)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
struct.error: 'h' format requires -32768 <= number <= 32767
Продемонстрируйте разницу между символами формата 's'
и 'c'
:
>>> pack("@ccc", b'1', b'2', b'3')
b'123'
>>> pack("@3s", b'123')
b'123'
Распакованные поля можно назвать, присвоив их переменным или обернув результат в именованный кортеж:
>>> 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
после упакованного '#'
были добавлены три байта NUL, чтобы выровнять следующее целое число по границе четырех байт. В этом примере вывод был произведен на машине с малым эндианом:
>>> pack('@ci', b'#', 0x12131415)
b'#\x00\x00\x00\x15\x14\x13\x12'
>>> pack('@ic', 0x12131415, b'#')
b'\x15\x14\x13\x12#'
>>> calcsize('@ci')
8
>>> calcsize('@ic')
5
Следующий формат 'llh0l'
приводит к тому, что в конце добавляются два байта pad, предполагая, что лонги платформы выровнены по 4-байтовым границам:
>>> pack('@llh0l', 1, 2, 3)
b'\x00\x00\x00\x01\x00\x00\x00\x02\x00\x03\x00\x00'
Приложения¶
Существует два основных применения модуля struct
: обмен данными между кодом на Python и C внутри приложения или другого приложения, скомпилированного с помощью того же компилятора (native formats), и обмен данными между приложениями с использованием согласованной компоновки данных (standard formats). Вообще говоря, строки формата, создаваемые для этих двух областей, отличаются друг от друга.
Родные форматы¶
При построении строк формата, имитирующих родную раскладку, компилятор и архитектура машины определяют порядок байтов и размер данных. В таких случаях следует использовать символ формата @
для указания собственного порядка байтов и размера данных. Внутренние байты-заглушки обычно вставляются автоматически. Возможно, в конце строки формата потребуется код формата с нулевым повтором для округления до нужной границы байта для правильного выравнивания последовательных блоков данных.
Рассмотрим два простых примера (на 64-битной, little-endian машине):
>>> calcsize('@lhl')
24
>>> calcsize('@llh')
18
В конце второй строки формата данные не дотягиваются до границы 8 байт без использования дополнительной прокладки. Код формата с нулевым повтором решает эту проблему:
>>> calcsize('@llh0l')
24
Для указания повтора можно использовать код формата 'x'
, но для родных форматов лучше использовать формат с нулевым повтором, например '0l'
.
По умолчанию используется собственное упорядочивание и выравнивание байтов, но лучше быть явным и использовать символ префикса '@'
.
Стандартные форматы¶
При обмене данными за пределами вашего процесса, например, в сети или хранилище, будьте точны. Указывайте точный порядок байтов, размер и выравнивание. Не предполагайте, что они соответствуют «родному» порядку конкретной машины. Например, порядок байтов в сети - big-endian, а во многих популярных процессорах - little-endian. Явное определение этого порядка позволяет пользователю не задумываться о специфике платформы, на которой выполняется его код. Первый символ обычно должен быть <
или >
(или !
). За добавление символов отвечает программист. Символ формата с нулевым повтором не работает. Вместо этого пользователь должен явно добавить байт 'x'
, где это необходимо. Обращаясь к примерам из предыдущего раздела, мы имеем:
>>> calcsize('<qh6xq')
24
>>> pack('<qh6xq', 1, 2, 3) == pack('@lhl', 1, 2, 3)
True
>>> calcsize('@llh')
18
>>> pack('@llh', 1, 2, 3) == pack('<qqh', 1, 2, 3)
True
>>> calcsize('<qqh6x')
24
>>> calcsize('@llh0l')
24
>>> pack('@llh0l', 1, 2, 3) == pack('<qqh6x', 1, 2, 3)
True
Приведенные выше результаты (выполненные на 64-битной машине) не гарантируют совпадения при выполнении на разных машинах. Например, приведенные ниже примеры были выполнены на 32-битной машине:
>>> calcsize('<qqh6x')
24
>>> calcsize('@llh0l')
12
>>> pack('@llh0l', 1, 2, 3) == pack('<qqh6x', 1, 2, 3)
False
Занятия¶
Модуль struct
также определяет следующий тип:
- class struct.Struct(format)¶
Возвращает новый объект Struct, который записывает и считывает двоичные данные в соответствии со строкой формата format. Однократное создание объекта
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
.Added in version 3.4.
- format¶
Строка формата, используемая для построения данного объекта Struct.
- size¶
Вычисленный размер структуры (и, следовательно, байтового объекта, созданного методом
pack()
), соответствующейformat
.
Изменено в версии 3.13: Изменилось значение repr() для структур. Теперь это:
>>> Struct('i') Struct('i')