Можно ли сделать то же самое, например, с 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
s, что означает, что они неизменяемы, поэтому вы не можете сделать это:
s1.C = s2
И самое главное, namedtuple
нельзя использовать как 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, поэтому... выбирайте меньшее из двух зол.
person
abarnert
schedule
26.04.2013
struct
, верно? Вы не можете сделать это напрямую, но два наиболее очевидных способа сделать это косвенно (встраивание вложенных структур вручную в строки формата или манипулирование данными вручную) работают. Подробности смотрите в моем обновленном ответе. (И если это не то, о чем вы спрашиваете, извините.) - person abarnert   schedule 29.04.2013