Spec-Zone.ru › Python 3.10

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-структуры. Выбор между использованием родного порядка байтов и заполнения или стандартных форматов зависит от приложения.

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

Символ

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

Размер

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

@

родной

родной

родной

=

родной

стандартный

нет

<

малый порядок байтов

стандартный

нет

>

большой порядок байтов

стандартный

нет

!

сетевой (= большой порядок байтов)

стандартный

нет

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

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

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

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

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

Форма '!' представляет собой сетевой порядок байтов, который всегда является большим порядком байтов, как определено в 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)

?

short

булево

1

(1)

h

_Bool

целое число

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 , определенному в C99. Если этот тип недоступен, он моделируется с помощью char. В стандартном режиме он всегда представлен одним байтом.
  2. При попытке упаковать нецелое число с использованием любого из кодов преобразования целых чисел, если нецелое число имеет метод __index__(), то этот метод вызывается для преобразования аргумента в целое число перед упаковкой.

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

  3. Коды преобразования 'n' и 'N' доступны только для размера по умолчанию (выбран по умолчанию или с символом порядка байтов '@'). Для стандартного размера можно использовать любой из других форматов целых чисел, который подходит для вашего приложения.
  4. Для кодов преобразования 'f', 'd' и 'e' упакованное представление использует формат IEEE 754 binary32, binary64 или binary16 (соответственно для 'f', 'd' или 'e') независимо от формата чисел с плавающей запятой, используемого платформой.
  5. Символ формата 'P' доступен только для порядка байтов по умолчанию (выбран по умолчанию или с символом порядка байтов '@'). Символ порядка байтов '=' выбирает использование порядка little-endian или big-endian в зависимости от системы. Модуль 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' кодирует «строку Паскаля», то есть короткую строку переменной длины, хранящуюся в фиксированном количестве байтов, заданном счетчиком. Первый сохраненный байт — это длина строки или 255, что меньше. За ним следуют байты строки. Если строка, переданная в pack(), слишком длинная (длиннее, чем счетчик минус 1), хранятся только ведущие count-1 байтов строки. Если строка короче count-1, она дополняется нулевыми байтами, чтобы использовалось ровно count байт. Обратите внимание, что для unpack() символ формата 'p' потребляет count байт, но возвращаемая строка никогда не может содержать более 255 байт.
  9. Для символа формата 's' счетчик интерпретируется как длина байтов, а не как счетчик повторений, как для других символов формата; например, '10s' означает одну строку из 10 байт, которая отображается или считывается как одна строка Python с байтами, в то время как '10c' означает 10 отдельных элементов по одному байту (например, cccccccccc) которые отображаются или считываются как десять разных байтовых объектов Python. (См. Примеры для конкретной демонстрации разницы.) Если счетчик не указан, он по умолчанию равен 1. При упаковке строка усекается или дополняется нулевыми байтами, чтобы она уместилась. При распаковке полученный объект байтов всегда имеет ровно указанное количество байтов. В качестве специального случая '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 в представлении булевых значений в формате по умолчанию или стандартном формате, а любое ненулевое значение будет равно 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 вызове ниже, что после упакованного '#' были добавлены три нулевых байта, чтобы выровнять следующее целое число по четырёхбайтовой границе. В этом примере вывод был произведён на машине с порядком байтов little endian:

>>> 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-битной машине с порядком байтов 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.

Компилированные объекты 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–2023 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.10/library/struct.html

Spec-Zone.ru

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