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

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

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

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

Форма '!' представляет собой сетевой порядок байтов, который всегда является big-endian, как определено в 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, определённому в 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 в зависимости от системы.
  6. Тип IEEE 754 binary16 «полуточной точности» был введён в 2008 году в стандарте IEEE 754. Он имеет бит знака, 5-битный экспонент и 11-битовую точность (с 10 битами, хранящимися явно), и может представлять числа в диапазоне от приблизительно 6.1e-05 до 6.5e+04 с полной точностью. Этот тип не широко поддерживается компиляторами C: на типичной машине для хранения можно использовать unsigned short, но не для математических операций. См. страницу Википедии о формате чисел с плавающей точкой полуточной точности для получения дополнительной информации.
  7. При упаковке 'x' вставляет один нулевой байт.
  8. Символ формата 'p' кодирует «строку Паскаля», то есть короткую строку переменной длины, хранящуюся в фиксированном количестве байтов, заданном счётчиком. Первый хранящийся байт — это длина строки или 255, что меньше. За ним следуют байты строки. Если строка, переданная в pack(), слишком длинная (длиннее, чем счётчик минус 1), хранятся только первые count-1 байтов строки. Если строка короче count-1, она дополняется нулевыми байтами, чтобы всего использовалось ровно count байт. Обратите внимание, что для unpack(), символ формата 'p' потребляет count байта, но возвращаемая строка никогда не может содержать более 255 байтов.
  9. Для символа формата '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 вызове ниже после упакованного '#' были добавлены три нулевых байта, чтобы выровнять последующее целое число по границе в четыре байта. В данном примере вывод был получен на машине с порядком байтов 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' приводит к добавлению двух байтов дополнения в конце, предполагая, что длинные целые числа платформы выровнены по границам в четыре байта:

>>> 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 поддерживают следующие методы и атрибуты:

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