Spec-Zone.ru › Python 3.14

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

Исходный код: Lib/struct.py

Этот модуль преобразует значения Python и структуры C, представленные в виде объектов Python bytes. Компактные строки формата описывают предполагаемые преобразования в значения Python и обратно. Функции и объекты модуля можно использовать для двух в значительной степени различных задач: обмена данными с внешними источниками (файлами или сетевыми соединениями) либо передачи данных между приложением Python и уровнем C.

Примечание

Если символ префикса не указан, по умолчанию используется нативный режим. Данные упаковываются или распаковываются с учетом платформы и компилятора, с помощью которых была собрана среда выполнения Python. Результат упаковки заданной структуры C включает байты-заполнители, обеспечивающие правильное выравнивание задействованных типов C; при распаковке выравнивание также учитывается. При обмене данными с внешними источниками, напротив, программист отвечает за определение порядка байтов и заполнителей между элементами. Подробности см. в разделе Порядок байтов, размер и выравнивание.

Несколько функций struct (и методы Struct) принимают аргумент buffer. Это объекты, реализующие протокол буфера и предоставляющие буфер только для чтения либо для чтения и записи. Чаще всего для этой цели используются типы 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 является обязательным. Отрицательное значение offset отсчитывается от конца buffer.

struct.unpack(format, buffer)

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

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

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

struct.iter_unpack(format, buffer)

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

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

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

struct.calcsize(format)

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

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

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

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

По умолчанию типы C представлены в нативном для машины формате и порядке байтов и правильно выровнены: при необходимости пропускаются байты-заполнители (согласно правилам компилятора C). Такое поведение выбрано для того, чтобы байты упакованной структуры точно соответствовали расположению в памяти соответствующей структуры C. Выбор между нативным порядком байтов и заполнителями и стандартными форматами зависит от приложения.

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

Символ

Порядок байтов

Размер

Выравнивание

@

нативный

нативный

нативное

=

нативный

стандартный

отсутствует

<

от младшего байта к старшему

стандартный

отсутствует

>

от старшего байта к младшему

стандартный

отсутствует

!

сетевой (= от старшего байта к младшему)

стандартный

отсутствует

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

Примечание

Число 1023 (0x3ff в шестнадцатеричной системе) представляется байтами следующим образом:

  • 03 ff в порядке от старшего байта к младшему (>)
  • ff 03 в порядке от младшего байта к старшему (<)

Пример на Python:

>>> import struct
>>> struct.pack('>h', 1023)
b'\x03\xff'
>>> struct.pack('<h', 1023)
b'\xff\x03'

Нативный порядок байтов может быть как от старшего байта к младшему, так и от младшего к старшему — это зависит от хост-системы. Например, Intel x86, AMD64 (x86-64) и Apple M1 используют порядок от младшего байта к старшему; IBM z и многие устаревшие архитектуры — от старшего байта к младшему. Используйте sys.byteorder, чтобы проверить порядок байтов в вашей системе.

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

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

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

Форма '!' обозначает сетевой порядок байтов, который всегда соответствует порядку от старшего байта к младшему, как определено в IETF RFC 1700.

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

Примечания:

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

Символы формата

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

Формат

Тип C

Тип Python

Стандартный размер

Примечания

x

байт-заполнитель

нет значения

(7)

c

char

байты длиной 1

1

b

signed char

int

1

(2)

B

unsigned char

int

1

(2)

?

_Bool

bool

1

(1)

h

short

int

2

(2)

H

unsigned short

int

2

(2)

i

int

int

4

(2)

I

unsigned int

int

4

(2)

l

long

int

4

(2)

L

unsigned long

int

4

(2)

q

long long

int

8

(2)

Q

unsigned long long

int

8

(2)

n

ssize_t

int

(2), (3)

N

size_t

int

(2), (3)

e

_Float16

float

2

(4), (6)

f

float

float

4

(4)

d

double

float

8

(4)

F

float complex

complex

8

(10)

D

double complex

complex

16

(10)

s

char[]

bytes

(9)

p

char[]

bytes

(8)

P

void*

int

(2), (5)

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

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

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

См. также

В модулях array и ctypes, а также в сторонних модулях, таких как numpy, используются похожие, но немного отличающиеся коды типов.

Примечания:

  1. Код преобразования '?' соответствует типу _Bool, определенному стандартами C начиная с C99. В стандартном режиме он представлен одним байтом.
  2. При попытке упаковать нецелое значение с помощью любого кода преобразования целых чисел, если у этого значения есть метод __index__(), этот метод вызывается для преобразования аргумента в целое число перед упаковкой.

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

  3. Коды преобразования 'n' и 'N' доступны только для нативного размера (выбирается по умолчанию или с помощью символа порядка байтов '@'). Для стандартного размера можно использовать любой другой целочисленный формат, подходящий для вашей задачи.
  4. Для кодов преобразования 'f', 'd' и 'e' упакованное представление использует форматы IEEE 754 binary32, binary64 или binary16 (соответственно для 'f', 'd' или 'e') независимо от формата чисел с плавающей точкой, используемого платформой.
  5. Символ формата 'P' доступен только для нативного порядка байтов (выбирается по умолчанию или с помощью символа порядка байтов '@'). Символ порядка байтов '=' выбирает порядок от младшего байта к старшему или от старшего к младшему в зависимости от хост-системы. Модуль struct не интерпретирует его как нативный порядок, поэтому формат 'P' недоступен.
  6. Тип IEEE 754 binary16 «половинной точности» был введен в редакции стандарта IEEE 754 2008 года. Он имеет знаковый бит, 5-битную экспоненту и точность 11 бит (из которых явно хранятся 10 бит) и позволяет представлять числа примерно от 6.1e-05 до 6.5e+04 с полной точностью. Этот тип широко не поддерживается компиляторами C: он доступен как тип _Float16, если компилятор поддерживает приложение H стандарта C23. На типичной машине для хранения можно использовать unsigned short, но не для математических операций. Подробнее см. страницу Википедии о формате чисел с плавающей точкой половинной точности.
  7. При упаковке 'x' добавляет один байт NUL.
  8. Символ формата 'p' кодирует «строку Паскаля», то есть строку переменной длины, хранящуюся в фиксированном количестве байтов, заданном счетчиком. Первый сохраненный байт — это длина строки или 255, если длина больше. Далее следуют байты строки. Если переданная в pack() байтовая строка слишком длинная (длиннее, чем счетчик минус 1), сохраняются только первые count-1 байтов строки. Если байтовая строка короче count-1, она дополняется нулевыми байтами, чтобы общее число использованных байтов точно соответствовало счетчику. Обратите внимание: при вызове unpack() символ формата 'p' считывает count байтов, однако возвращаемый объект bytes не может содержать более 255 байтов. При упаковке принимаются аргументы типов bytes и bytearray.
  9. Для символа формата 's' счетчик задает длину байтовой строки, а не количество повторений, как для остальных символов формата. Например, '10s' означает одну строку длиной 10 байтов, соответствующую одной байтовой строке Python, тогда как '10c' означает 10 отдельных односимвольных элементов (например, cccccccccc), соответствующих десяти различным байтовым объектам Python. (Наглядный пример этого различия см. в разделе Примеры.) Если счетчик не указан, по умолчанию он равен 1. При упаковке байтовая строка усекается или дополняется нулевыми байтами, чтобы соответствовать заданной длине. При распаковке результирующий объект bytes всегда содержит ровно заданное число байтов. В особом случае '0s' означает одну пустую байтовую строку (а '0c' — 0 символов). При упаковке принимаются аргументы типов bytes и bytearray.
  10. Для символов формата 'F' и 'D' упакованное представление использует форматы IEEE 754 binary32 и binary64 для компонентов комплексного числа независимо от формата чисел с плавающей точкой, используемого платформой. Обратите внимание, что комплексные типы (F и D) доступны всегда, хотя в C комплексные типы являются необязательной возможностью. Согласно стандарту C11 каждый комплексный тип представлен массивом C из двух элементов, содержащим соответственно действительную и мнимую части.

Перед символом формата может указываться целое число повторений. Например, строка формата '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.

Примеры

Примечание

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

Упакуйте и распакуйте целые числа трех различных размеров, используя порядок от старшего байта к младшему:

>>> 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 ниже после упакованного '#' были добавлены три нулевых байта, чтобы выровнять следующее целое число по четырехбайтовой границе. В этом примере результат получен на машине с порядком байтов от младшего к старшему:

>>> 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' приводит к добавлению двух байтов-заполнителей в конце, если предположить, что длинные целые числа на платформе выровнены по четырехбайтовой границе:

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

См. также

Module array

Упакованное бинарное хранение однородных данных.

Module json

Кодировщик и декодировщик JSON.

Module pickle

Сериализация объектов Python.

Применение

У модуля struct есть два основных назначения: обмен данными между кодом Python и кодом C в пределах одного приложения или другого приложения, скомпилированного тем же компилятором (нативные форматы), а также обмен данными между приложениями с согласованной структурой данных (стандартные форматы). Как правило, строки формата для этих двух задач различаются.

Нативные форматы

При создании строк формата, имитирующих нативные структуры данных, порядок байтов и заполнители определяются компилятором и архитектурой машины. В таких случаях для указания нативного порядка байтов и размеров данных следует использовать символ формата @. Внутренние байты-заполнители обычно вставляются автоматически. Чтобы округлить размер до нужной границы байтов и правильно выровнять следующие блоки данных, в конце строки формата может понадобиться код формата с нулевым числом повторений.

Рассмотрим два простых примера (на 64-разрядной машине с порядком байтов от младшего к старшему):

>>> calcsize('@lhl')
24
>>> calcsize('@llh')
18

Без дополнительного заполнителя данные в конце второй строки формата не выравниваются по 8-байтовой границе. Эту проблему решает код формата с нулевым числом повторений:

>>> calcsize('@llh0l')
24

Для задания числа повторений можно использовать код формата 'x', однако для нативных форматов лучше использовать формат с нулевым числом повторений, например '0l'.

По умолчанию используется нативный порядок байтов и выравнивание, однако лучше указывать их явно с помощью символа префикса '@'.

Стандартные форматы

При обмене данными за пределами вашего процесса, например по сети или при хранении, указывайте точные параметры. Задавайте порядок байтов, размер и выравнивание явно. Не следует предполагать, что они совпадают с нативным порядком конкретной машины. Например, в сетевом порядке байты расположены от старшего к младшему, тогда как многие популярные процессоры используют порядок от младшего к старшему. Если определить это явно, пользователю не придется учитывать особенности платформы, на которой выполняется код. Обычно первым символом должен быть < или > (либо !). За заполнители отвечает программист. Символ формата с нулевым числом повторений здесь не подойдет. Вместо этого пользователь должен явно добавить '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.

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

format

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

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

size

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

Изменено в версии 3.13: Представление repr() структур изменилось. Теперь оно выглядит так:

>>> Struct('i')
Struct('i')

© 2001 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.14/library/struct.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API