Spec-Zone.ru › Python 3.13

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

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

Символ

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

Размер

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

@

родной

родной

родной

=

родной

стандартный

отсутствует

<

маленький конец

стандартный

отсутствует

>

большой конец

стандартный

отсутствует

!

сетевой (= большой конец)

стандартный

отсутствует

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

Примечание

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

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)

float

2

(4)

f

float

float

4

(4)

d

double

float

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' доступен только для естественного порядка байтов (выбранного по умолчанию или с символом порядка байтов '@'). Символ порядка байтов '=' выбирает порядок little-endian или big-endian в зависимости от хост-системы. Модуль struct не интерпретирует это как естественный порядок, поэтому формат 'P' недоступен.
  6. Тип IEEE 754 binary16 «полуточная точность» был введен в пересмотре стандарта IEEE 754 2008 года (IEEE 754 standard). Он имеет бит знака, 5-битный экспоненту и 11-битную точность (с 10 битами, явно сохраненными), и может представлять числа приблизительно от 6.1e-05 до 6.5e+04 с полной точностью. Этот тип не широко поддерживается компиляторами C: на типичном компьютере для хранения может использоваться unsigned short, но не для математических операций. Подробнее см. страницу Википедии о формате с плавающей точкой half-precision floating-point format.
  7. При упаковке 'x' вставляет один байт NUL.
  8. Символ формата 'p' кодирует «строку Паскаля», то есть короткую строку переменной длины, хранящуюся в фиксированном количестве байт, заданном счетчиком. Первый сохраненный байт — это длина строки или 255, что меньше. За ним следуют байты строки. Если строка, переданная в pack(), слишком длинная (длиннее, чем счетчик минус 1), хранятся только первые count-1 байтов строки. Если строка короче count-1, она дополняется нулевыми байтами до тех пор, пока не будут использованы ровно count байтов. Обратите внимание, что для unpack() символ формата 'p' потребляет count байта, но возвращаемая строка никогда не может содержать более 255 байтов.
  9. Для символа формата 's' значение count интерпретируется как длина байтов, а не как повторяющийся счетчик, как для других символов формата; например, '10s' означает одну строку длиной 10 байт, которая отображается или преобразуется в одну строку Python байтов, а '10c' означает 10 отдельных однобайтовых элементов символов (например, cccccccccc) отображающихся или преобразующихся в десять различных объектов байтов Python. (Примеры конкретной демонстрации разницы см. в разделе Примеры). Если count не указан, он по умолчанию равен 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 в представлении типа 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 вызов ниже, что три нулевых байта были добавлены после упакованного '#' для выравнивания следующего целого числа на границе в четыре байта. В этом примере вывод был получен на машине с 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, который записывает и считывает двоичные данные в соответствии со строкой формата формат. Создание объекта 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(), использующей скомпилированный формат. Размер буфера в байтах, начиная с позиции смещение, должен быть не меньше size.

iter_unpack(buffer)

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

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

format

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

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

size

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

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

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

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

Spec-Zone.ru

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