2013-04-26 4 views
1

Так что я два простых ctypes STRUCTпитона ctypes против namedtuple

class S2 (ctypes.Structure): 
    _fields_ = [ 
    ('A2',  ctypes.c_uint16*10), 
    ('B2',  ctypes.c_uint32*10), 
    ('C2',  ctypes.c_uint32*10) ] 


class S1 (ctypes.Structure): 
    _fields_ = [ 
    ('A',  ctypes.c_uint16), 
    ('B',  ctypes.c_uint32), 
    ('C',  S2) ] 

Можно ли это сделать то же самое, например, с namedtuple? Как списки обрабатываются в namedtuple?

Edit:

использования struc.pack

test_data = '0100000002000000' + 10*'01' + 10*'01' + 10*'01' 

S2 = collections.namedtuple('S2', ['A2', 'B2', 'C2']) 
S1 = collections.namedtuple('S1', ['A', 'B', 'REF_to_S2']) 

Data2 = S2._make(struct.unpack('10p10p10p', binascii.unhexlify(test_data[16:]))) 
##this is not working, because there must be 3 args.. 
Data1 = S1._make(struct.unpack('ii', binascii.unhexlify(test_data[0:16]))) 

В конце концов, я хочу, чтобы распечатать данные в удобном для чтения формата (имеющий пар ключа: значение видимого). Но теперь я не могу понять, как мне обрабатывать эту операцию распаковки с двумя разными именами?

Эта операция unpack.struct позаботится о том, чтобы тип значения возникал, правильно?

+7

Что вы планируете делать с этими структурами? Вы передаете их в C-функции или просто используете их в python? Кроме того, вам нужно гарантировать тип полей? Наконец, насколько я могу судить, объекты структуры изменяемы, а namedtuple - нет. – mgilson

+0

Просто внутри python, но я хотел бы быть уверенным, что поля и принятые значения одного типа. – Juster

+0

Чтобы уточнить: что вы в конечном счете задаете, как обращаться с вложенными структурами в 'struct', правильно? Вы не можете сделать это напрямую, но два наиболее очевидных способа сделать это косвенно (встраивать вложенные структуры вручную в строках формата или вручную манипулировать данными вручную), оба работают. Дополнительную информацию см. В моем обновленном ответе. (И если это не то, о чем вы просите, извините.) – abarnert

ответ

4

Можно ли это сделать, например, с 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, поэтому ... выберите то, что вы найдете в меньшем количестве из двух зол.

+0

Я не знаю, считать ли этот ответ доблестным или безрассудным. Я имею в виду, что вопрос, вероятно, не заслуживает ответа, пока не будет предоставлена ​​информация, запрошенная комментарием @ mgilson. –

+0

Спасибо, да, что stuct.pack - это то, что мне нужно. Но я не могу понять, как я должен указать, что последнее значение в s1 является ссылкой на структуру s2. – Juster

+0

@Juster: Хорошо, я думаю, что у меня есть ручка того, что вы просите, поэтому позвольте мне отредактировать ответ. – abarnert

Смежные вопросы