python ctypes与namedtuple

python ctypes与namedtuple,python,namedtuple,Python,Namedtuple,所以我有两个简单的ctypes结构 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

所以我有两个简单的ctypes结构

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中如何处理列表

编辑:

结构包使用

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])))
最后,我希望以可读的格式打印数据(使key:value对可见)。但是现在我想不出我应该如何用两个不同的名称来处理解包操作

这个unpack.struct操作将处理值类型问题,对吗

例如,使用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')
另外,请注意,即使是第一个示例也实际创建了10个
ctypes
值的
list
s,而不是
ctypes
数组。如果你想这样做,你必须显式地转换它们


其次,
namedtuple
s是
tuple
s的扩展,这意味着它们是不可变的,所以不能这样做:

s1.C = s2

最重要的是,
名为tuple
不能用作
ctypes.Structure
——不能将其传递给C函数,如果要将其序列化为特定的二进制格式,必须编写手动逻辑(例如,绕过
struct.pack


在namedtuple中如何处理列表

如上所述,
namedtuple
的成员不是静态类型的,可以保存任何类型的值。因此,它们的处理方式与它们在
元组
列表
、普通类实例、全局变量等中的处理方式相同。只要在其中粘贴一个
列表
,就得到了一个
列表


是的,那是我需要的。但我不知道如何指出s1中的最后一个值是对s2结构的引用

namedtuple
端,您只需使用
S2
实例作为
S1.C
的值,如上面的示例所示。同样地,
namedtuple
的项/属性与Python中的任何其他属性/变量等一样,只是包含对象引用的名称。因此,
s1=s1(1,2,s2)
将使
s1
的第三项变成对
s2
引用的同一对象的另一个引用

至于如何使用
struct
序列化数据:
struct
模块没有任何方法直接委托给嵌入式对象。但是,由于
pack
的输出只是一个
字节
(或者在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.\u 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级别组合对象,因此…选择两个缺点中较小的一个

例如,使用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')
另外,请注意,即使是第一个示例,实际上也创建了10个
ctypes
值的
list
s,而不是
ctypes
数组。如果需要,必须显式转换它们


其次,
namedtuple
s是
tuple
s的扩展,这意味着它们是不可变的,所以不能这样做:

s1.C = s2

最重要的是,
名为tuple
不能用作
ctypes.Structure
——不能将其传递给C函数,如果要将其序列化为特定的二进制格式,必须编写手动逻辑(例如,绕过
struct.pack


在namedtuple中如何处理列表

如上所述,
名为tuple
的成员不是静态类型的,可以保存任何类型的值。因此,它们的处理方式与
元组、
列表、普通类实例、全局变量等中的处理方式相同。只需在其中粘贴一个
列表
,就得到了一个
列表


是的,stuct.pack是我需要的。但是我不知道如何指出s1中的最后一个值是对s2结构的引用

namedtuple
方面,您只需使用
S2
实例作为
S1.C
的值,如我上面的示例所示。同样地,
namedtuple
的项/属性与Python中的任何其他属性/变量/etc一样。在Python中,只是包含对象引用的名称。因此,
S1=S1(1,2,S2)
将把
s1
的第三项变成对
s2
引用的同一对象的另一个引用

至于如何使用
struct
来序列化数据:
struct
模块没有任何方法直接委托给嵌入式对象。但是由于
pack
的输出只是一个
bytes
(或者在Python2.x中,
str
)对象,您可以使用普通的字符串manipul来实现这一点