首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >python ctype vs namedtuple

python ctype vs namedtuple
EN

Stack Overflow用户
提问于 2013-04-26 18:41:15
回答 1查看 760关注 0票数 1

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

代码语言:javascript
复制
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) ]

是否有可能这样做,例如,对名称?列表是如何用名称处理的?

编辑:

struc.pack使用

代码语言:javascript
复制
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操作将处理值类型问题,对吗?

EN

回答 1

Stack Overflow用户

发布于 2013-04-26 19:16:39

是否有可能这样做,例如,对名称?

这取决于你所说的“相同”是什么意思。您可以使用相同的字段轻松地创建namedtuple类型:

代码语言:javascript
复制
S2 = collections.namedtuple('S2', ['A2', 'B2', 'C2'])
S1 = collections.namedtuple('S1', ['A', 'B', 'C'])

然而,他们显然不是相同的类型,不会有相同的行为。

首先,这些字段是一般的Python属性(也是普通的tuple成员),这意味着它们没有静态类型;它们可以保存任何类型的值。

所以,你可以这样做:

代码语言:javascript
复制
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)

但你也可以这样做:

代码语言:javascript
复制
s2 = S2('a', 'b', 'c')
s1 = S1('d', 'e', s2)

…甚至:

代码语言:javascript
复制
s1 = S1('d', 'e', 'f')

还要注意的是,即使是第一个示例也实际上创建了10个list值的ctypes,而不是ctypes数组。如果你想要的话,你必须显式地投出它们。

其次,namedtuples是tuples的扩展,这意味着它们是不可变的,所以您不能这样做:

代码语言:javascript
复制
s1.C = s2

最重要的是,namedtuple不能用作ctypes.Structure-you不能将它传递给C函数,如果您想以某种特定的二进制格式序列化它,则必须编写手动逻辑(例如,围绕struct.pack),等等。

列表是如何用名称处理的?

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

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

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

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

代码语言:javascript
复制
# 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,但由于文档反复使用后者,我想这一定是…的预定方法)

或者,您可以手动平平格式字符串:

代码语言:javascript
复制
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上组合对象,所以…选择两种罪恶中较小的一种。

票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/16243160

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档