Можно ли это сделать, например, с namedtuple?
Это зависит от того, что вы подразумеваете под «тем же». Вы можете легко создавать namedtuple
типы с теми же полями:
S2 = collections.namedtuple('S2', ['A2', 'B2', 'C2'])
S1 = collections.namedtuple('S1', ['A', 'B', 'C'])
Однако, они, очевидно, не тот же тип, и не будет иметь такое же поведение.
Во-первых, эти поля являются нормальные атрибуты Python (а также нормальные tuple
членов), что означает, что они не имеют статические типы; они могут содержать значения любого типа.
Таким образом, вы можете сделать это:
s2 = S2([ctypes.c_uint16(i) for i in range(10)],
[ctypes.c_uint32(i) for i in range(10)],
[ctypes.c_uint32(i) for i in range(10)])
s1 = S1(ctypes.c_uint16(1), ctypes.c_uint32(2), s2)
Но вы также можете сделать это:
s2 = S2('a', 'b', 'c')
s1 = S1('d', 'e', s2)
... или даже:
s1 = S1('d', 'e', 'f')
А также, обратите внимание, что даже первый пример фактически создан list
s из 10 ctypes
значения, а не ctypes
массивы. Если вы этого хотите, вы должны их явно указать.
Во-вторых, namedtuple
s являются продолжением tuple
с, что означает, что они неизменны, так что вы не можете сделать это:
s1.C = s2
И самое главное, namedtuple
может 't использовать как ctypes.Structure
- вы не можете передать его функции C, вам нужно написать ручную логику (например, около struct.pack
), если вы хотите сериализовать ее в определенном двоичном формате и т. д.
Как списки обрабатываются в namedtuple?
Как указано выше, члены namedtuple
не статически типизированы и могут хранить значения любого типа. Таким образом, они обрабатываются так же, как и у tuple
, list
, обычного экземпляра класса, глобальной переменной и т. Д. Просто вставьте list
, и у вас есть list
.
да что stuct.pack это то, что мне нужно. Но я не могу понять, как я должен указать, что последнее значение в s1 является ссылкой на структуру s2.
С namedtuple
стороны, вы просто использовать S2
экземпляр в качестве значения для S1.C
, как в моих примерах выше. Опять же, элементы/атрибуты namedtuple
точно так же, как и любые другие атрибуты/переменные/и т. Д. в Python, просто имена, содержащие ссылки на объекты. Таким образом, s1 = S1(1, 2, s2)
сделает третий элемент s1
в другую ссылку на тот же объект, к которому относится s2
.
Как использовать struct
для сериализации данных: Модуль struct
не имеет возможности напрямую делегировать встроенный объект. Но так как выход pack
просто bytes
(или, в Python 2.x, str
) объект, вы можете сделать это с нормальными строками:
# version 1
s2_struct = struct.Struct('!HII')
s1_header = struct.Struct('!HI')
def pack_s2(s2):
return s2_struct.pack(s2.A2, s2.B2, s2.C2)
def unpack_s2(s2):
return S2._make(s2_struct.unpack(s2))
def pack_s1(s1):
return s1_header.pack(s1.A, s1.B) + pack_s2(s1.C)
def unpack_S1(s1):
offset = len(s1_header)
a, b = s1_header.unpack(s1[:offset])
c = unpack_s2(s1[offset:])
return S1._make(a, b, c)
(лично я бы использовать S2(*struct.unpack
вместо S2._make
, но поскольку документация делает последний раз, я думаю, что должен быть предназначен способ сделать вещи ...)
в качестве альтернативы, вы можете разгладить строки форматирования вручную:
s2_struct = struct.Struct('!HII')
s1_struct = struct.Struct('!HIHII')
def pack_s2(s2):
return s2_struct.pack(s2.A2, s2.B2, s2.C2)
def pack_s1(s1):
return s1_struct.pack(s1.A, s1.B, s1.C.A2, s1.C.B2, s1.C.C2)
def unpack_s2(s2):
return S2._make(s2_struct.unpack(s2))
def unpack_S1(s1):
a, b, a2, b2, c2 = s1_struct.unpack(s1)
c = S2(a2, b2, c2)
return S1(a, b, c)
Я думаю, что вторая версия легче читать, но также легче ошибиться и требует, чтобы вы думали о создании объектов на двоичном уровне, а не на уровне Python, поэтому ... выберите то, что вы найдете в меньшем количестве из двух зол.
Что вы планируете делать с этими структурами? Вы передаете их в C-функции или просто используете их в python? Кроме того, вам нужно гарантировать тип полей? Наконец, насколько я могу судить, объекты структуры изменяемы, а namedtuple - нет. – mgilson
Просто внутри python, но я хотел бы быть уверенным, что поля и принятые значения одного типа. – Juster
Чтобы уточнить: что вы в конечном счете задаете, как обращаться с вложенными структурами в 'struct', правильно? Вы не можете сделать это напрямую, но два наиболее очевидных способа сделать это косвенно (встраивать вложенные структуры вручную в строках формата или вручную манипулировать данными вручную), оба работают. Дополнительную информацию см. В моем обновленном ответе. (И если это не то, о чем вы просите, извините.) – abarnert