Spec-Zone.ru › Python 3.11

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)

?

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

Компилированные объекты 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.

New in version 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.11/library/struct.html

Spec-Zone.ru

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