Spec-Zone.ru › Python 3.12

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 является обязательным.

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)

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

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

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

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

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

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

Символ

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

Размер

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

@

нативный

нативный

нативное

=

нативный

стандартный

нет

<

от младшего к старшему (little-endian)

стандартный

нет

>

от старшего к младшему (big-endian)

стандартный

нет

!

сетевой (= big-endian)

стандартный

нет

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

Примечание

Число 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

целое число

1

(1), (2)

B

unsigned char

целое число

1

(2)

?

_Bool

логическое значение

1

(1)

h

short

целое число

2

(2)

H

unsigned short

целое число

2

(2)

i

int

целое число

4

(2)

I

unsigned int

целое число

4

(2)

l

long

целое число

4

(2)

L

unsigned long

целое число

4

(2)

q

long long

целое число

8

(2)

Q

unsigned long long

целое число

8

(2)

n

ssize_t

целое число

(3)

N

size_t

целое число

(3)

e

(6)

число с плавающей точкой

2

(4)

f

float

число с плавающей точкой

4

(4)

d

double

число с плавающей точкой

8

(4)

s

char[]

байты

(9)

p

char[]

байты

(8)

P

void*

целое число

(5)

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

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

Примечания:

  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: на типичной машине для хранения можно использовать unsigned short, но не для математических операций. Дополнительные сведения см. на странице Википедии, посвящённой формату чисел с плавающей точкой половинной точности.
  7. При упаковке 'x' вставляет один байт NUL.
  8. Символ формата 'p' кодирует «строку Pascal», то есть строку переменной длины, хранящуюся в фиксированном количестве байтов, заданном счётчиком. Первый сохранённый байт содержит длину строки или число 255, если длина больше. За ним следуют байты строки. Если строка, переданная в pack(), слишком длинная (длиннее, чем счётчик минус 1), сохраняются только первые count-1 байтов строки. Если строка короче count-1, она дополняется нулевыми байтами, чтобы общее количество использованных байтов точно соответствовало счётчику. Обратите внимание: при вызове unpack() символ формата 'p' занимает count байтов, однако возвращаемая строка не может содержать более 255 байтов.
  9. Для символа формата 's' счётчик интерпретируется как длина байтов, а не как число повторений, как для остальных символов формата; например, '10s' означает одну строку длиной 10 байтов, преобразуемую в одну строку байтов Python или обратно, тогда как '10c' означает 10 отдельных односимвольных элементов длиной в один байт (например, cccccccccc), преобразуемых в десять разных объектов bytes 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.

Примеры

Примечание

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

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

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

>>> 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

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

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

Spec-Zone.ru

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