我创建了一个整数数组,我希望它们能够被我创建的结构定义解释
from ctypes import *
from array import array
class MyStruct(Structure):
_fields_ = [("init", c_uint),
("state", c_char),
("constant", c_int),
("address", c_uint),
("size", c_uint),
("sizeMax", c_uint),
("start", c_uint),
("end", c_uint),
("timestamp", c_uint),
("location", c_uint),
("nStrings", c_uint),
("nStringsMax", c_uint),
("maxWords", c_uint),
("sizeFree", c_uint),
("stringSizeMax", c_uint),
("stringSizeFree", c_uint),
("recordCount", c_uint),
("categories", c_uint),
("events", c_uint),
("wraps", c_uint),
("consumed", c_uint),
("resolution", c_uint),
("previousStamp", c_uint),
("maxTimeStamp", c_uint),
("threshold", c_uint),
("notification", c_uint),
("version", c_ubyte)]
# arr = array.array('I', [1])
# How can I do this?
# mystr = MyStruct(arr) magic
# (mystr.helloworld == 1) == True
我可以做以下事情:
mystr = MyStruct()
rest = array.array('I')
with open('myfile.bin', 'rb') as binaryFile:
binaryFile.readinto(mystr)
rest.fromstring(binaryFile.read())
# Now create another struct with rest
rest.readinto(mystr) # Does not work
如果数据包含在array.array('I')中,如何避免使用文件将Ints数组转换为结构?我不确定Structure构造函数接受什么或readinto如何工作。
答案 0 :(得分:1)
Star-unpacking将起作用,但前提是结构中的所有字段都是整数类型。在Python 2.x中,c_char
无法从int
初始化(它在3.5中工作正常)。如果您将state
的类型更改为c_byte
,那么您可以执行以下操作:
mystr = MyStruct(*myarr)
这实际上并没有受益于任何array
特定魔法(在解压缩步骤中,这些值会暂时转换为Python int
,因此您不会减少峰值内存使用量),如果初始化所述array
比直接读入结构更容易,那么你只需要array
。
如果你去明星解包路线,那么阅读.state
现在会得到int
值,而不是len {1}}值。如果您要使用str
进行初始化,但只读取一个字符int
,则可以使用str
中包含的受保护名称:
property
通过定义自己转换了class MyStruct(Structure):
_fields_ = [...
("_state", c_byte), # "Protected" name int-like; constructor expects int
...]
@property
def state(self):
return chr(self._state)
@state.setter
def state(self, x):
if isinstance(x, basestring):
x = ord(x)
self._state = x
参数传递的property
,可以在没有__init__
的情况下使用类似的技术:
state
class MyStruct(Structure):
_fields_ = [("init", c_uint),
("state", c_char),
...]
def __init__(self, init=0, state=b'\0', *args, **kwargs):
if not isinstance(state, basestring):
state = chr(state)
super(MyStruct, self).__init__(init, state, *args, **kwargs)
- 类似于减少临时工作的解决方案您可以使用某些memcpy
特定魔法来避免临时Python级别array
(并且无需将int
更改为state
)而无需真正的文件对象使用伪(内存中)文件类对象:
c_byte
这只能起作用,因为您的非import io
mystr = MyStruct() # Default initialize
# Use BytesIO to gain the ability to write the raw bytes to the struct
# because BytesIO's readinto isn't finicky about exact buffer formats
io.BytesIO(myarr.tostring()).readinto(mystr)
# In Python 3, where array implements the buffer protocol, you can simplify to:
io.BytesIO(myarr).readinto(mystr)
# This still performs two memcpys (one occurs internally in BytesIO), but
# it's faster by avoiding a Python level method call
宽度属性后跟c_int
宽度属性(因此它们无论如何都要填充到四个字节);如果你有两个c_int
/ c_ubyte
/等。类型背靠背,然后你有问题(因为c_char
的一个值会初始化结构中的两个字段,这似乎不是你想要的。)
如果您使用的是Python 3,那么您可以从array
特定魔法中受益,以避免解包和array
技术的两步memcpy
的成本(来自{{1} } - > BytesIO
- > struct)。它在Py3中工作,因为Py3的array
类型支持缓冲协议(它在Py2中没有),并且因为Py3' bytes
具有array
允许您更改memoryview
格式以使其与cast
直接兼容的方法:
memoryview
与array
解决方案一样,这只能起作用,因为你的字段碰巧填充到四个字节大小
性能方面,明星解包赢得少量字段,但对于大量字段(您的案例有几十个),基于直接mystr = MyStruct() # Default initialize
# Make a view on mystr's underlying memory that behaves like a C array of
# unsigned ints in native format (matching array's type code)
# then perform a "memcpy" like operation using empty slice assignment
# to avoid creating any Python level values.
memoryview(mystr).cast('B').cast('I')[:] = myarr
的方法胜出;在23个字段类的测试中,BytesIO
解决方案赢得了我的Python 2.7安装上的星形解包因子2.5倍(星形解包为2.5微秒,memcpy
为1微秒)。
BytesIO
解决方案与BytesIO
解决方案类似,但从3.5开始,它比memoryview
方法略慢(可能是需要构建的结果)几个临时BytesIO
来执行必要的转换操作和/或BytesIO
切片分配代码是许多可能格式的通用目的,所以它在实现中不简单memoryview
。 memoryview
可能会针对更大的副本进行更好的扩展(如果损失是由于固定的memcpy
开销造成的),但是您很少有足够重要的结构;它只会出现在memoryview
可能获胜的更通用的复制场景(来往cast
数组之类)。
答案 1 :(得分:0)
这必须是一个数组吗?你可以使用一个清单吗?您可以从列表中解压缩到可以使用*运算符的函数:
mystr = MyStruct(* arr)
或dict:
mystr = MyStruct(** arr)